I have a function that throws an error, in this function I have a inside a
closure that I need to throw the error from it's completion handler. Is that possible ?
Here is my code so far.
enum CalendarEventError: ErrorType {
case UnAuthorized
case AccessDenied
case Failed
}
func insertEventToDefaultCalendar(event :EKEvent) throws {
let eventStore = EKEventStore()
switch EKEventStore.authorizationStatusForEntityType(.Event) {
case .Authorized:
do {
try insertEvent(eventStore, event: event)
} catch {
throw CalendarEventError.Failed
}
case .Denied:
throw CalendarEventError.AccessDenied
case .NotDetermined:
eventStore.requestAccessToEntityType(EKEntityType.Event, completion: { (granted, error) -> Void in
if granted {
//insertEvent(eventStore)
} else {
//throw CalendarEventError.AccessDenied
}
})
default:
}
}
requestAccessToEntityType
does its work asynchronously. When the completion handler is eventually run your function already returned. Therefore it is not possible to throw an error from the closure the way you are suggesting.You should probably refactor the code so that the authorization part is handled separately from the event insertion and only call
insertEventToDefaultCalendar
when you know the authorization status is as expected/required.If you really want to handle everyhing in one function, you could use a semaphore (or a similar technique) so that the asynchronous code part behaves synchronously with regard to your function.
That's not possible in this case - that completion handler would have to be declared with
throws
(and the method withrethrows
) and this one is not.Note that all that throwing is just a different notations for
NSError **
in Objective-C (inout error parameter). The Objective-C callback doesn't have an inout parameter so there is no way to pass the error up.You will have to use a different method to handle errors.
In general,
NSError **
in Obj-C orthrows
in Swift don't play well with asynchronous methods because the error handling works synchronously.Because throwing is synchronous, an async function that wants to throw must have an inner closure that throws, such as this:
Then, at the call site, you use it like this:
You can not make function with
throw
, but return aclosure
with status or error! If it's not clear I can give some code.When you define closure that throws:
then type of this closure is
() throws -> ()
and function that takes this closure as parameter must have the same parameter type:It this function you can call
completion
closure synchronous:and you have to add
throws
keyword to function signature or call completion withtry!
:or asynchronous:
In last case you will not be able to catch error.
So if
completion
closure ineventStore.requestAccessToEntityType
method and the method itself does not havethrows
in its signature or ifcompletion
is called asynchronously then you can notthrow
from this closure.I suggest you the following implementation of your function that passes error to callback instead of throwing it: