You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开启严格并发与Swift 6后,PhotosPickerItem转Data报错求助

解决PhotosPickerItem在严格并发模式下的数据竞争警告

问题原因

开启complete严格并发模式并升级到Swift 6后,PhotosPickerItem属于主Actor隔离类型(绑定的@State属性默认归主Actor管理)。在.task(id: selectedPhoto)的非隔离闭包中直接访问selectedPhoto?.loadTransferable(type: Data.self),会触发跨Actor访问隔离值的数据竞争风险警告。

解决方案

确保访问PhotosPickerItem的代码在主Actor上下文中执行,两种简洁实现方式:

方式1:给task闭包标记@MainActor

直接为.task的闭包添加@MainActor属性,强制闭内代码在主Actor上运行:

.task(id: selectedPhoto) { @MainActor in
    if let data = try? await selectedPhoto?.loadTransferable(type: Data.self) {
        selectedPhotoData = data
    }
}

方式2:用MainActor.run包裹访问逻辑

若不想给整个闭包标记主Actor,可将访问selectedPhoto的代码包裹在MainActor.run中:

.task(id: selectedPhoto) {
    await MainActor.run {
        if let data = try? await selectedPhoto?.loadTransferable(type: Data.self) {
            selectedPhotoData = data
        }
    }
}

修正后的完整代码(含拼写错误修复)

View部分

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 AddModel { // 修正:原代码误写为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()
            }
            // 应用解决方案:标记闭包为@MainActor
            .task(id: selectedPhoto) { @MainActor in
                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 {
                viewModel.addModel(image: selectedPhotoData) // 修正:原代码误写为viewiewModel
                dismiss()
            } label: {
                Text("Save")
            }
        }
    }
}

ViewModel部分

@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(model) // 修正:原代码误写为insert(shoe)
        
        save()
    }

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

    private func save() {
        do {
            try modelContext.save()
        } catch {
            print("Saving context failed, \(error.localizedDescription)")
        }
        
        fetchModels()
    }
}

内容的提问来源于stack exchange,提问作者Robert Basamac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 02:49:58