严格并发和 Swift 6 在尝试将 PhotosPickerItem 转换为 Data 时会产生错误

问题描述 投票:0回答:1

我有下面的视图,我想使用 PhotosPicker 从图库加载图像并将其显示给用户。我还想将图像转换为数据,以便我可以将其存储在 SwiftData 数据库中。

更新到 iOS 18、xcode 16.0 beta 并将严格并发从最小更改为完整,并将 swift 版本从 5 更改为 6 后,我在

Sending main actor-isolated value of type 'PhotosPickerItem' with later accesses to nonisolated context risks causing data races
线上收到错误
if let data = try? await selectedPhoto?.loadTransferable(type: Data.self)

我还有很多错误,但我设法改掉了它们。该应用程序按预期工作,但我不知道如何解决此错误。

任何帮助将不胜感激。

注意:为了简单起见,我从下面的代码中删除了

Model
的所有其他属性。

struct AddModel: View {
    
    @Environment(ViewModel.self) private var viewModel
    @Environment(\.dismiss) private var dismiss
    
    @State private var showPhotosPicker: Bool = false
    
    @State private var selectedPhoto: PhotosPickerItem?
    @State private var selectedPhotoData: Data?
    
    var body: some View {
        Form {
            photoSection
        }
        .toolbar {
            toolbarItems
        }
    }
}

// MARK: - View Components

extension AddShoeView {
    
    @ViewBuilder
    private var photoSection: some View {
        Section {
            VStack(spacing: 12) {
                ZStack {
                    if let selectedPhotoData, let uiImage = UIImage(data: selectedPhotoData) {
                        Image(uiImage: uiImage)
                            .resizable()
                            .scaledToFill()
                            .frame(width: 150, height: 150)
                            .clipShape(RoundedRectangle(cornerRadius: 12))
                    } else {
                        Image(systemName: "square.fill")
                            .resizable()
                            .foregroundStyle(.secondary)
                            .frame(width: 150, height: 150)
                            .clipShape(RoundedRectangle(cornerRadius: 12))
                    }
                }
                
                Text("Add Photo")
                    .font(.callout)
                    .fontWeight(.semibold)
                    .foregroundStyle(.white)
                    .padding(.horizontal, 12)
                    .padding(.vertical, 8)
                    .background(Color(uiColor: .secondarySystemBackground))
                    .cornerRadius(20)
            }
            .frame(maxWidth: .infinity)
            .photosPicker(isPresented: $showPhotosPicker, selection: $selectedPhoto, photoLibrary: .shared())
            .onTapGesture {
                showPhotosPicker.toggle()
            }
            .task(id: selectedPhoto) {
                if let data = try? await selectedPhoto?.loadTransferable(type: Data.self) {
                    selectedPhotoData = data
                }
            }
        }
        .listRowBackground(Color.clear)
        .listRowInsets(EdgeInsets())
    }
    
    
    @ToolbarContentBuilder
    private var toolbarItems: some ToolbarContent {
        ToolbarItem(placement: .confirmationAction) {
            Button {
                viewiewModel.addModel(image: selectedPhotoData)
                dismiss()
            } label: {
                Text("Save")
            }
        }
    }
}
@Observable
final class ViewModel: {
    
    @ObservationIgnored private var modelContext: ModelContext
    
    private(set) var models: [Model] = []
    
    init(modelContext: ModelContext) {
        self.modelContext = modelContext
        fetchModels()
    }
        
    func addModel(image: Data?) {
        let model = Model(image: image)

        modelContext.insert(shoe)
        
        save()
    }

    private func fetchModels() {
        do {
            let descriptor = FetchDescriptor<Model>()
            self.models = try modelContext.fetch(descriptor)
        } catch {
            print("Fetching shoes failed, \(error.localizedDescription)")
        }        
    }

    private func save() {
        do {
            try modelContext.save()
        } catch {
            print("Saving context failed, \(error.localizedDescription)")
        }
        
        fetchModels()
    }
}
ios swift swiftui concurrency
1个回答
0
投票

MainActor
添加到
View

@MainActor
struct AddModel: View {

这是 iOS 18+ 中的标准配置,但必须添加到早期版本的

View
中。

© www.soinside.com 2019 - 2024. All rights reserved.