我正在尝试解决编译错误:
Task or actor isolated value cannot be sent
在使用带有 Swift 6 的 Xcode 16.0 beta 3 和Complete
启用并发时。我的代码:
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)
}
}
虽然我通常理解
[CNContact]
数组无法从非隔离上下文发送到 MainActor
上下文,因为 CNContact
是不可发送的,但目前还不清楚如何解决这个问题。 (这个问题在早期的 Xcode 16 beta 中没有出现)。
我想可以用复制的数据创建我自己的
CNContact
传真结构,但这似乎是一笔令人讨厌的开销。我还尝试了 MainActor.assumeIsolated
以及 WWDC 2024 Swift Concurrency 视频中讨论的其他策略 https://developer.apple.com/wwdc24/10169,但这些方法似乎都不起作用。
如有任何帮助,我们将不胜感激。
首先您应该知道哪些类型可以安全地声明为
Sendable
。
值类型
没有可变存储的引用类型
内部管理对其状态的访问的引用类型
函数和闭包(通过用 @Sendable 标记它们)
将
CNContact
标记为 Sendable
就可以了
CNContact 对象存储联系人信息的不可变副本,因此您无法直接更改此对象中的信息。联系人对象是线程安全的,因此您可以从应用程序的任何线程访问它们。
请注意,
View
和Coordinator
可以通过@MainActor
变得安全,它们不需要Sendable
。
import SwiftUI
import Contacts
import ContactsUI
struct ContactsView: View {
@State private var selected: [CNContact] = []
var body: some View {
SimpleContactPicker(selectedContacts: $selected)
}
}
#Preview {
ContactsView()
}
struct SimpleContactPicker: View {
let allowedContactType: CNContactType? = CNContactType.person
@Binding var selectedContacts: [CNContact]
var body: some View {
SimpleContactPickerProxy(allowedContactType: self.allowedContactType, selectedContacts: $selectedContacts)
.ignoresSafeArea()
}
}
struct SimpleContactPickerProxy: UIViewControllerRepresentable {
typealias UIViewControllerType = CNContactPickerViewController
let allowedContactType: CNContactType?
@Binding var selectedContacts: [CNContact]
@MainActor
final class Coordinator: NSObject, CNContactPickerDelegate {
var parent: SimpleContactPickerProxy
init(_ parent: SimpleContactPickerProxy) {
self.parent = parent
}
nonisolated func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
}
nonisolated func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
Task { @MainActor in
parent.selectedContacts = contacts
}
}
}
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)
}
}
extension CNContactType {
var predicateForEnablingContact: NSPredicate {
NSPredicate(format: "contactType=\(self.rawValue)")
}
}
extension CNContact: @unchecked @retroactive Sendable {}