使用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 } }
代码说明
- Coordinator的作用:作为引用类型对象,负责持有
AVPlayer和处理播放结束通知,解决了值类型无法适配Objective-C通知系统的问题。 - 手动创建SKView:不再依赖Storyboard的IBOutlet,直接在
makeUIView中创建并配置SKView属性。 - 资源清理:通过
dismantleUIView方法移除通知观察者并释放AVPlayer,避免内存泄漏。 - 视频节点定位:将视频节点居中放置,适配Scene尺寸,避免位置偏移问题。
内容的提问来源于stack exchange,提问作者sivafe9540
相关产品推荐
相关产品推荐

