我想使用
enumerateContacts(with:usingBlock:)
和 async/await
方法获取用户的联系人。这是我的功能:
func fetchContacts() async throws -> [Contact] {
let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactEmailAddressesKey]
let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor])
let store = CNContactStore()
let contactsActor = ContactsActor()
var contactsArray: [Contact] = []
return try await withCheckedThrowingContinuation { continuation in
DispatchQueue.global(qos: .background).async {
do{
try store.enumerateContacts(with: request) { contact, stop in
let contact = Contact(
givenName: contact.givenName,
familyName: contact.familyName,
emails: contact.emailAddresses.map { $0.value as String }
)
Task {
await contactsActor.appendToContacts(contact: contact)
}
}
continuation.resume(returning: contactsArray )
} catch {
continuation.resume(throwing: error)
}
}
}
}
我也在使用这个演员:
actor ContactsActor {
var contacts:[Contact] = []
func appendToContacts(contact: Contact) {
contacts.append(contact)
}
func getContact()-> [Contact]{
return contacts
}
}
在 viewDidLoad 方法中,我在任务中调用
fetchContacts
函数:
Task {
let contacts = try await fetchContacts()
await MainActor.run(body: {
self.contactsTable.reloadData()
})
}
我收到此错误:
在并发执行的代码中引用捕获的 var 'contactsArray'。
在
continuation.resume(returning: contactsArray )
前面
我正在学习快速并发,但我不知道如何解决这个错误。任何帮助将不胜感激。
我希望在名为
Contact
的自定义结构数组中获取用户的联系人。
我会避免使用 GCD API,而是遵循 Swift 并发模式(例如分离任务):
func fetchContacts() async throws -> [Contact] {
let task = Task.detached {
let keys = [
CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactEmailAddressesKey as CNKeyDescriptor
]
let request = CNContactFetchRequest(keysToFetch: keys)
let store = CNContactStore()
let formatter = CNContactFormatter()
formatter.style = .fullName
var contacts: [Contact] = []
try store.enumerateContacts(with: request) { contact, stop in
guard !Task.isCancelled else {
stop.pointee = true
return
}
let contact = Contact(
givenName: contact.givenName,
familyName: contact.familyName,
fullName: formatter.string(from: contact),
emails: contact.emailAddresses.map { $0.value as String }
)
contacts.append(contact)
}
try Task.checkCancellation()
return contacts
}
return try await withTaskCancellationHandler {
try await task.value
} onCancel: {
task.cancel()
}
}
以上我也支持取消
Task.isCancelled
;和CancellationError
投掷 Task.checkCancellation()
。另外,如果你原谅我,我为你的
Contact
类型引入了一个额外的全名参数,并使用 CNContactFormatter
来构建这个字符串。这是个人喜好的问题,所以在那里做你喜欢做的事。这与更广泛的问题无关。