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

Swift 6编译错误:Task/Actor隔离值无法发送的解决咨询

解决Xcode 16 Beta 3 + Swift 6并发完整模式下Task or actor isolated value cannot be sent编译错误

问题概述

使用Xcode 16.0 beta 3、Swift 6并启用Complete Concurrency模式时,编译触发错误:Task or actor isolated value cannot be sent。错误发生在CNContactPickerDelegate的回调方法中,尝试将非Sendable类型的[CNContact]数组赋值给MainActor隔离的@Binding属性时出现。此前Xcode 16早期beta版本未出现该问题,尝试过自定义CNContact复制结构体、MainActor.assumeIsolated等WWDC2024提及的策略均无效。

错误代码

import SwiftUI
@preconcurrency import Contacts
import ContactsUI

struct SimpleContactPicker: View {
    
    let allowedContactType: CNContactType? = CNContactType.person
    
    @Binding var selectedContacts: [CNContact]?

    var body: some View {
        SimpleContactPickerProxy(allowedContactType: self.allowedContactType, selectedContacts: $selectedContacts)
            .ignoresSafeArea()
    }
}

extension CNContactType {
    
    var predicateForEnablingContact: NSPredicate {
        
        NSPredicate(format: "contactType=\(self.rawValue)")
    }
}

struct SimpleContactPickerProxy: UIViewControllerRepresentable, @unchecked Sendable {
    
    typealias UIViewControllerType = CNContactPickerViewController
    
    let allowedContactType: CNContactType?
    
    @Binding var selectedContacts: [CNContact]?

    final class Coordinator: NSObject, CNContactPickerDelegate, @unchecked Sendable {
        var parent: SimpleContactPickerProxy

        init(_ parent: SimpleContactPickerProxy) {
            self.parent = parent
        }
        
        func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
        }

        func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
           
            Task { @MainActor in
                self.parent.selectedContacts = contacts // <<-- ERROR: Task or actor isolated value cannot be sent
            }
        }
    }
    
    func makeUIViewController(context: Context) -> CNContactPickerViewController {
        
        let contactPickerViewController = CNContactPickerViewController()
        
        contactPickerViewController.delegate = context.coordinator
        
        if let allowedContactType {
            contactPickerViewController.predicateForEnablingContact = allowedContactType.predicateForEnablingContact
        }
        
        return contactPickerViewController
    }
    
    func updateUIViewController(_ uiViewController: CNContactPickerViewController, context: Context) {
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
}

解决方案

方案1:使用unsafeTransfer绕过Sendable检查(推荐)

CNContact是不可变类型,本质上线程安全,只是苹果未将其标记为Sendable。使用Swift 6新增的unsafeTransfer函数,明确告知编译器我们保证该值的线程安全性,从而绕过并发检查:

func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
    Task { @MainActor in
        self.parent.selectedContacts = unsafeTransfer(contacts)
    }
}

方案2:将更新逻辑封装到MainActor标记的方法中

在Coordinator中定义被@MainActor标记的方法处理属性更新,同时用unsafeTransfer传递非Sendable的数组:

final class Coordinator: NSObject, CNContactPickerDelegate, @unchecked Sendable {
    var parent: SimpleContactPickerProxy

    init(_ parent: SimpleContactPickerProxy) {
        self.parent = parent
    }
    
    func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
    }

    func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
        updateSelectedContacts(unsafeTransfer(contacts))
    }
    
    @MainActor
    private func updateSelectedContacts(_ contacts: [CNContact]) {
        parent.selectedContacts = contacts
    }
}

方案3:确认回调线程后直接赋值(简化版)

UIKit的CNContactPickerDelegate代理方法默认在主线程执行,可直接去掉Task { @MainActor in }包裹赋值:

func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
    self.parent.selectedContacts = contacts
}

注意:若后续Contacts框架变更回调线程,该方案可能引发线程安全问题,建议优先使用前两种方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 14:35:19