升级到 Swift 6 后,我的照片应用出现了问题。在下面的示例中,我遇到了此错误(无法从 Sendable 闭包中引用主参与者隔离属性“photoImage”)。有人知道如何解决这个问题吗?在启动时在 .task 中将其分配给其他值也不起作用。

import SwiftUI
import PhotosUI

@Observable
final class CameraModel {
    var thumbnail: String?
}

struct ContentView: View {
    @State var camera = CameraModel()
    @State var selectedItems: [PhotosPickerItem] = []
    var body: some View {
        PhotosPicker(selection: $selectedItems, photoLibrary: .shared()) {
           // I’m getting an error here
            photoImage
        }
    }
    
    
    @ViewBuilder
    private var photoImage: some View {
        if let thumbnail = camera.thumbnail {
            Image(thumbnail)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .animation(.easeInOut(duration: 0.3), value: thumbnail)
        } else {
            Image(systemName: "photo.on.rectangle")
        }
    }
}

#Preview {
    ContentView(camera: CameraModel())
}

2

  • 我知道这不是最好的解决方案,但如果photoImagePhotosPicker闭包中内联实现,它会起作用吗?


    – 

  • 向 Apple 提交错误。UI 应该被隔离


    – 


最佳答案
2

一种可能的解决方法是停用 actor-isolated 属性并创建一个单独的View。我们也可以使用捕获列表thumbnail从 actor-isolated 中获取camera

struct ContentView: View {
    @State var camera = CameraModel()
    @State var selectedItems: [PhotosPickerItem] = []

    var body: some View {
        PhotosPicker(selection: $selectedItems, photoLibrary: .shared()) { [thumbnail = camera.thumbnail] in
            PhotoImage(thumbnail: thumbnail)
        }
    }
}

struct PhotoImage: View {
    let thumbnail: String?

    var body: some View {
        if let thumbnail {
            Image(thumbnail)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .animation(.easeInOut(duration: 0.3), value: thumbnail)
        } else {
            Image(systemName: "photo.on.rectangle")
        }
    }
}

1

  • 嘿,我其实也在想类似的事情,但忘了将其作为副本 [thumbnail = camera.thumbnail] 传递。非常感谢!


    – 

只需标记您的photoImage即可nonisolated,因为协议View标记为@MainActor所以它的所有属性都绑定到MainActor。闭包标签的类型是 just @Sendable label: () -> Label,它不是独立的上下文,所以您需要标记nonisolated。但在这里你不能引用 State 和非 Sendable 属性photoImage

struct ContentView: View {
    //@State var camera = CameraModel()
    @State var selectedItems: [PhotosPickerItem] = []
    var body: some View {
        PhotosPicker(selection: $selectedItems, photoLibrary: .shared(), label: {
            photoImage
        })
    }
    
    
    @ViewBuilder
    nonisolated private var photoImage: some View { //<- mark here
        ...
    }
}

另一个修复方法是捕获缩略图属性并在闭包中构造 View:

@Observable
final class CameraModel {
    var thumbnail: String?
}

struct ContentView: View {
    @State var camera = CameraModel()
    @State var selectedItems: [PhotosPickerItem] = []
    var body: some View {
        PhotosPicker(selection: $selectedItems, photoLibrary: .shared()) { [thumbnail = camera.thumbnail] in
           // I’m getting an error here
            if let thumbnail {
                Image(thumbnail)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .animation(.easeInOut(duration: 0.3), value: thumbnail)
            } else {
                Image(systemName: "photo.on.rectangle")
            }
        }
    }
}

0