【问题标题】:Cannot assign to property: 'self' is immutable in UIViewControllerRepresentable无法分配给属性:“self”在 UIViewControllerRepresentable 中是不可变的
【发布时间】:2019-11-25 17:18:51
【问题描述】:

我有以下代码sn-p:

struct player : UIViewControllerRepresentable {
    
    var url : String
    var player1: AVPlayer
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<player>) -> AVPlayerViewController {
        let controller = AVPlayerViewController()
        player1 = AVPlayer(url: URL(string: url)!)
        controller.player = player1
        return controller
    }
    
    func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<player>) {
    }
    
    func pause() {
        player1.pause()
    }
}

这给出了错误:

'无法分配给属性:'self' 是不可变的'

我需要在 makeUIViewController 函数之外拥有 AVPlayer,因为我需要从 pause 函数中访问它。我该怎么做?

【问题讨论】:

    标签: swift swiftui


    【解决方案1】:

    您看到的错误是由于结构是值类型,并且它们上的任何更改其属性的方法都需要标记为mutating。不幸的是,您不能标记makeUIViewController,因为它是在UIViewControllerRepresentable 协议中定义的,但有一个相当简单的解决方案。

    您实际上只是使用 url 来构造一个AVPlayer - 没有必要坚持下去。为您的结构编写和初始化程序,该结构接受一个 url 字符串并构造一个 AVPlayer。我已将AVPlayer 设为可选,因为URL(string: String) 返回Optional URL(您可以想象并非所有字符串都是有效的url)。以下代码按预期工作:

    struct Player: UIViewControllerRepresentable {
    
        var player1: AVPlayer?
    
        public init(url string: String) {
            guard let url = URL(string: string) else {
                self.player1 = nil
                return
            }
            self.player1 = AVPlayer(url: url)
        }
    
        func makeUIViewController(context: UIViewControllerRepresentableContext<Player>) -> AVPlayerViewController {
            let controller = AVPlayerViewController()
            controller.player = player1
            return controller
        }
    
        func updateUIViewController(_ uiViewController: AVPlayerViewController,
                                    context: UIViewControllerRepresentableContext<Player>) {}
    
        func pause() {
            player1?.pause()
        }
    }
    

    附注:Swift 中的所有类型名称(类、结构、枚举)按照惯例都是大写的:你的结构应该被称为Player 而不是player。 您还应该查看 Cordinator 以获得 UIViewControllerRepresentable - 您需要一些东西来充当您的 AVPlayerViewControllerDelegate

    【讨论】:

      【解决方案2】:

      有几种可能可供选择(实际上它不是一个完整的选项列表,但希望它会有所帮助)

      选项1:在初始化器中执行

      struct player : UIViewControllerRepresentable {
      
          private var url : String
          private var player1: AVPlayer
      
          init(url: String) {
              self.url = url
              self.player1 = AVPlayer(url: URL(string: url)!)
          }
      
          func makeUIViewController(context: UIViewControllerRepresentableContext<player>) -> AVPlayerViewController {
              let controller = AVPlayerViewController()
              controller.player = player1
              return controller
          }
      
          func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<player>) {
          }
      }
      

      选项2:在第一次请求更新控制器时执行此操作

      struct player : UIViewControllerRepresentable {
      
          var url : String
          var player1: AVPlayer
      
          func makeUIViewController(context: UIViewControllerRepresentableContext<player>) -> AVPlayerViewController {
              return AVPlayerViewController()
          }
      
          func updateUIViewController(_ playerController: AVPlayerViewController, context: UIViewControllerRepresentableContext<player>) {
              if playerController.player == nil {
                  playerController.player = AVPlayer(url: URL(string: url)!)
              }
          }
      }
      

      选项3:如果您需要在生命周期内修改player1,那么您需要将其保存在某个外部实体中,例如ObservableObject,因为您的player 是View 结构,不能自行修改,实际上是编译器错误中所说的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-12-02
        • 1970-01-01
        • 2022-12-05
        • 1970-01-01
        • 2015-12-07
        • 1970-01-01
        • 1970-01-01
        • 2018-01-08
        相关资源
        最近更新 更多