I have very simple class which fetches the contacts. Now I need to create this function with throws.
As store.requestAccess
is not throwing function so I can't throw any error from that clousure.
So I am getting this error
Invalid conversion from throwing function of type '(_, _) throws -> ()' to non-throwing function type '(Bool, Error?) -> Void'
class ContactFetcher {
enum ContactError:Error {
case permissionError
case fetchError
}
func fetchContacts(completion:@escaping(([CNContact]) -> ())) throws {
let keys = [CNContactPhoneNumbersKey] as [CNKeyDescriptor]
let fetchRequest = CNContactFetchRequest(keysToFetch: keys)
let store = CNContactStore()
var results:[CNContact] = []
store.requestAccess(for: .contacts) { (grant, error) in
if grant{
do {
try store.enumerateContacts(with: fetchRequest, usingBlock: { (contact, stop) -> Void in
results.append(contact)
})
} catch {
// throw ContactError.fetchError
}
completion(results)
} else {
throw ContactError.permissionError
print("Error \(error)")
}
}
}
}
Is there any way to fix this ?
Thanks in advance
You cannot throw from within the non throwing completion handler. It is asynchronous! Just as you cannot return a value from within an asynchronous function, so too you cannot throw there. After all, to catch the throw, the throw would need to travel backwards in time to when the original function was called. And that is metaphysically impossible.
Instead you must provide another completion handler such that you can call it with an Error parameter from within the non throwing completion handler. That is exactly why the Result type was invented, to allow you to propagate an error through an asynchronous situation.