Swift 无法分配给属性:';自我';在UIViewControllerRepresentable中是不可变的

Swift 无法分配给属性:';自我';在UIViewControllerRepresentable中是不可变的,swift,swiftui,Swift,Swiftui,我有以下代码片段: struct player : UIViewControllerRepresentable { var url : String var player1: AVPlayer func makeUIViewController(context: UIViewControllerRepresentableContext<player>) -> AVPlayerViewController { let c

我有以下代码片段:

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()
    }
}
struct player:UIViewControllerRepresentable{
var url:String
var播放器1:AVPlayer
func makeUIViewController(上下文:UIViewControllerRepresentableContext)->AVPlayerViewController{
let controller=avplayervewcontroller()
player1=AVPlayer(url:url(string:url)!)
controller.player=player1
返回控制器
}
func updateUIViewController(uViewController:AVPlayServiceWController,上下文:UIViewControllerRepresentableContext){
}
函数暂停(){
player1.暂停()
}
}
这会产生以下错误:

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


我需要将AVPlayer置于makeUIViewController函数之外,因为我需要从暂停函数访问它。我怎样才能做到这一点呢?

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

选项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>) {
    }
}
struct player:UIViewControllerRepresentable{
私有变量url:String
私人var播放器1:AVPlayer
init(url:String){
self.url=url
self.player1=AVPlayer(url:url(string:url)!)
}
func makeUIViewController(上下文:UIViewControllerRepresentableContext)->AVPlayerViewController{
let controller=avplayervewcontroller()
controller.player=player1
返回控制器
}
func updateUIViewController(uViewController:AVPlayServiceWController,上下文:UIViewControllerRepresentableContext){
}
}
选项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)!)
        }
    }
}
struct player:UIViewControllerRepresentable{
var url:String
var播放器1:AVPlayer
func makeUIViewController(上下文:UIViewControllerRepresentableContext)->AVPlayerViewController{
返回avplayervewcontroller()
}
func UPDATEUIVEWCONTROLLER(uPlayerController:AVPlayerServiceWController,上下文:UIViewControllerRepresentableContext){
如果playerController.player==nil{
playerController.player=AVPlayer(url:url(字符串:url)!)
}
}
}

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

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

实际上,您只使用url来构造一个
AVPlayer
——不需要保留它。为您的结构编写并初始化一个url字符串,并构造一个
AVPlayer
。我已经将
AVPlayer
设置为可选的
URL(string:string)
返回一个
可选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()
    }
}
struct Player:UIViewControllerRepresentable{
var播放器1:AVPlayer?
公共初始化(url字符串:字符串){
guard let url=url(string:string)else{
self.player1=nil
返回
}
self.player1=AVPlayer(url:url)
}
func makeUIViewController(上下文:UIViewControllerRepresentableContext)->AVPlayerViewController{
let controller=avplayervewcontroller()
controller.player=player1
返回控制器
}
func updateUIViewController(uUIVIEWCONTROLLER:AVPlayerViewController,
上下文:UIViewControllerRepresentableContext){}
函数暂停(){
播放者1?暂停()
}
}
旁注:Swift中的所有类型名称(类、结构、枚举)按惯例都是大写的:您的结构应该被称为
Player
而不是
Player
。 您还应该查看
UIViewControllerRepresentable
Cordinator
——您需要一些东西来充当您的
avplayervewcontrollerdelegate