无法分配给属性:“self”在 UIViewControllerRepresentable 中是不可变的

Posted

技术标签:

【中文标题】无法分配给属性:“self”在 UIViewControllerRepresentable 中是不可变的【英文标题】:Cannot assign to property: 'self' is immutable in 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 函数中访问它。我该怎么做?

【问题讨论】:

【参考方案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 结构,不能自行修改,实际上是编译器错误中所说的。

【讨论】:

以上是关于无法分配给属性:“self”在 UIViewControllerRepresentable 中是不可变的的主要内容,如果未能解决你的问题,请参考以下文章

ios 将 self 分配给另一个类中的属性

将本地变量分配给属性时的内存泄漏弧

无法分配给属性:“popupHeight”是一个只能获取的属性

无法分配给属性:“操作”是仅获取属性

无法分配给对象的只读属性

在 SwiftUI 视图中设置计算属性无法编译