不能在 属性 初始值设定项中使用实例成员 'videoName'; 属性 初始值设定项 运行 在 'self' 可用之前

Cannot use instance member 'videoName' within property initializer; property initializers run before 'self' is available

我是 SwiftUI 的新手,我 运行 遇到了这个问题,因为我正在尝试使用 Model 中的 videoName 显示视频。 在 player = AVPlayer(...)(第 4 行)中,我不想通过字符串“squats”查找资源,而是想使用 Model 中的 videoName。如果我更换它们,我会得到错误

Cannot use instance member 'videoName' within property initializer; property initializers run before 'self' is available

谁能帮帮我?

这是我的代码:

struct ExercisingSessionView: View {
    
    let exerciseName: String
    let videoName: String
    
    @State var player = AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "squats", ofType: "mov")!))
    @State var isplaying = false
    @State var showcontrols = false
    
    var body: some View {
        
        CustomVideoPlayer(player: $player)
            .frame(width: 390, height: 219)
            .onTapGesture {
                self.showcontrols = true
                
            }
    }
    
    struct CustomVideoPlayer : UIViewControllerRepresentable {
        
        @Binding var player: AVPlayer
        
        func makeUIViewController(context: UIViewControllerRepresentableContext<CustomVideoPlayer>) -> AVPlayerViewController {
            
            let controller = AVPlayerViewController()
            controller.player = player
            controller.showsPlaybackControls = false
            return controller
        }
        
        func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<CustomVideoPlayer>) {
            
        }
    }
}

选项 1:

为您的 View 创建一个初始值设定项来创建您的 @State 初始值:

struct ExercisingSessionView: View {
    
    let exerciseName: String
    let videoName: String
    
    @State var player : AVPlayer
    @State var isplaying = false
    @State var showcontrols = false
    
    init(exerciseName: String, videoName: String) {
        self.exerciseName = exerciseName
        self.videoName = videoName
        self._player = State(initialValue: AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: videoName, ofType: "mov")!)))
    }
    
    var body: some View {
        CustomVideoPlayer(player: $player)
            .frame(width: 390, height: 219)
            .onTapGesture {
                self.showcontrols = true
            }
    }
}

这样做的缺点是,如果 ExercisingSessionView 经常被初始化(即使它没有真正重新呈现到视图层次结构),您在 init 中做着繁重的工作,这通常对性能来说是一个非常糟糕的主意。

选项 2:

声明player为可选,并在onAppear中加载初始值:



struct ExercisingSessionView: View {
    
    let exerciseName: String
    let videoName: String
    
    @State var player : AVPlayer?
    @State var isplaying = false
    @State var showcontrols = false
    
    var body: some View {
        Group {
            if let player = player {
                CustomVideoPlayer(player: player)
                    .frame(width: 390, height: 219)
                    .onTapGesture {
                        self.showcontrols = true
                    }
            }
        }.onAppear {
            player = AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: videoName, ofType: "mov")!))
        }
    }
}

struct CustomVideoPlayer : UIViewControllerRepresentable {
    var player: AVPlayer
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<CustomVideoPlayer>) -> AVPlayerViewController {
        
        let controller = AVPlayerViewController()
        controller.player = player
        controller.showsPlaybackControls = false
        return controller
    }
    
    func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<CustomVideoPlayer>) {
        
    }
}

这避免了选项 1 中的问题,因为 onAppear 只会被调用一次。

请注意,在这里,我在 CustomVideoPlayer 中制作了 player 一个常规的、非绑定的 属性 -- 因为 AVPlayer 是一个 class ,通过引用传递,没有理由使用 @Binding

您可以将您的名字传递给您的自定义视图。

struct ExercisingSessionView: View {
    
    let exerciseName: String
    let videoName: String
    
    @State var isplaying = false
    @State var showcontrols = false
    
    var body: some View {
        
        CustomVideoPlayer(player: videoName)
            .frame(width: 390, height: 219)
            .onTapGesture {
                self.showcontrols = true
                
            }
    }
    
    struct CustomVideoPlayer : UIViewControllerRepresentable {
        
        let videoName: String
        
        func makeUIViewController(context: UIViewControllerRepresentableContext<CustomVideoPlayer>) -> AVPlayerViewController {
            
            let controller = AVPlayerViewController()
            controller.player = AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: videoName, ofType: "mov")!))
            controller.showsPlaybackControls = false
            return controller
        }
}

当您将 squats 替换为 videoName:

时,我假设错误发生在这一行

@State var player = AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "squats", ofType: "mov")!))

您收到错误的原因是调用此行代码时未定义 videoName

要解决此问题,您可以在您定义的自定义 init 方法中设置属性。像这样:

    let videoName: String
    @State var player: AVPlayer
    
    init(exerciseName: String, videoName: String) {
        self.exerciseName = exerciseName
        self.videoName = videoName
        self.player = AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: videoName, ofType: "mov")!))
    }

请记住,您必须添加