You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用UIViewRepresentable无法将UIKit代码转为SwiftUI视图求助

问题分析与解决方案

你的SwiftUI代码存在多个核心错误,导致无法正常运行,以下是问题拆解和修正方案:

关键错误点

  • 返回类型不匹配:makeUIView声明返回UITextView,但实际需要返回的是SKView,类型完全不符。
  • 错误的代码结构:在makeUIView函数内定义@IBOutlet、override viewDidLoad无效——makeUIView是普通函数,并非ViewController的方法,且SKView需要手动创建,不能依赖Storyboard的IBOutlet。
  • 观察者目标错误:不能用self(UIViewRepresentable的struct是值类型)作为Objective-C通知的观察者,必须借助引用类型的Coordinator来处理。
  • 生命周期管理缺失:videoPlayer等对象未被正确持有,会被提前释放导致视频无法播放。

修正后的完整代码

import SwiftUI
import SpriteKit
import AVFoundation

struct TransparentVideoLoop: UIViewRepresentable {
    // 自定义Coordinator,管理通知与AVPlayer生命周期
    class Coordinator: NSObject {
        var videoPlayer: AVPlayer?
        
        @objc func playerItemDidReachEnd(notification: Notification) {
            if let playerItem = notification.object as? AVPlayerItem {
                playerItem.seek(to: CMTime.zero, completionHandler: nil)
            }
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    func makeUIView(context: Context) -> SKView {
        let skView = SKView()
        skView.backgroundColor = .clear
        
        // 加载并展示SKScene
        guard let scene = SKScene(fileNamed: "backgroundScene") else {
            print("Could not create a background scene")
            return skView
        }
        scene.scaleMode = .aspectFill
        skView.presentScene(scene)
        
        // 加载视频资源
        guard let alphaMovieURL = Bundle.main.url(forResource: "camera_city_animated", withExtension: "mov") else {
            print("Failed to overlay alpha movie on the background")
            return skView
        }
        
        // 初始化AVPlayer并添加到Scene
        let videoPlayer = AVPlayer(url: alphaMovieURL)
        context.coordinator.videoPlayer = videoPlayer // 让Coordinator持有player,避免提前释放
        
        let videoNode = SKVideoNode(avPlayer: videoPlayer)
        videoNode.size = skView.bounds.size
        videoNode.position = CGPoint(x: scene.size.width/2, y: scene.size.height/2) // 居中放置视频节点
        scene.addChild(videoNode)
        
        // 配置循环播放
        videoPlayer.actionAtItemEnd = .none
        NotificationCenter.default.addObserver(
            context.coordinator,
            selector: #selector(Coordinator.playerItemDidReachEnd(notification:)),
            name: .AVPlayerItemDidPlayToEndTime,
            object: videoPlayer.currentItem
        )
        
        // 启动播放
        videoPlayer.play()
        
        return skView
    }
    
    func updateUIView(_ uiView: SKView, context: Context) {
        // 视图更新时的逻辑(按需添加)
    }
    
    static func dismantleUIView(_ uiView: SKView, coordinator: Coordinator) {
        // 清理资源,避免内存泄漏
        NotificationCenter.default.removeObserver(coordinator)
        coordinator.videoPlayer?.pause()
        coordinator.videoPlayer = nil
    }
}

代码说明

  1. Coordinator的作用:作为引用类型对象,负责持有AVPlayer和处理播放结束通知,解决了值类型无法适配Objective-C通知系统的问题。
  2. 手动创建SKView:不再依赖Storyboard的IBOutlet,直接在makeUIView中创建并配置SKView属性。
  3. 资源清理:通过dismantleUIView方法移除通知观察者并释放AVPlayer,避免内存泄漏。
  4. 视频节点定位:将视频节点居中放置,适配Scene尺寸,避免位置偏移问题。

内容的提问来源于stack exchange,提问作者sivafe9540

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 17:06:21