【问题标题】:Cannot use instance member 'videoName' within property initializer; property initializers run before 'self' is available不能在属性初始化程序中使用实例成员“videoName”;属性初始化程序在 'self' 可用之前运行
【发布时间】:2021-10-02 14:03:27
【问题描述】:

我对 SwiftUI 很陌生,当我尝试使用 Model 中的 videoName 显示视频时遇到了这个问题。 在 player = AVPlayer(...)(line 4) 中,我不想通过字符串“squats”查找资源,而是想使用 Model 中的 videoName。如果我替换它们,我会收到错误

不能在属性初始化器中使用实例成员“videoName”;属性初始化器在“self”可用之前运行

谁能帮帮我?

这是我的代码:

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>) {
            
        }
    }
}

【问题讨论】:

    标签: swiftui model video-player


    【解决方案1】:

    选项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 是一个类,通过引用传递,没有理由与它一起使用 @Binding .

    【讨论】:

      【解决方案2】:

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

      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
              }
      }
      

      【讨论】:

        【解决方案3】:

        当您将 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")!))
            }
        

        记住,你必须添加

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-19
          • 2021-04-03
          • 1970-01-01
          • 2017-09-18
          • 2020-06-18
          • 1970-01-01
          相关资源
          最近更新 更多