我有一个抛出错误的函数,在这个函数中我有一个true
闭包,我需要从它的完成处理程序中抛出错误。这可能吗?
到目前为止,这是我的代码。
inside a
答案 0 :(得分:12)
定义抛出的闭包时:
enum MyError: ErrorType {
case Failed
}
let closure = {
throw MyError.Failed
}
然后这个闭包的类型是() throws -> ()
,并且将此闭包作为参数的函数必须具有相同的参数类型:
func myFunction(completion: () throws -> ()) {
}
这个函数你可以调用completion
闭包同步:
func myFunction(completion: () throws -> ()) throws {
completion()
}
您必须使用throws
将try!
关键字添加到功能签名或致电完成中:
func myFunction(completion: () throws -> ()) {
try! completion()
}
或异步:
func myFunction(completion: () throws -> ()) {
dispatch_async(dispatch_get_main_queue(), { try! completion() })
}
在最后一种情况下,您将无法捕获错误。
因此,如果completion
方法中的eventStore.requestAccessToEntityType
封闭且方法本身在其签名中没有throws
,或者异步调用completion
那么你就不能{{1来自这个闭包。
我建议您使用以下函数实现,它将错误传递给回调而不是抛出它:
throw
答案 1 :(得分:6)
在这种情况下不可能 - 完成处理程序必须使用throws
(以及rethrows
的方法)声明,而这个不是。
请注意,所有抛出只是Objective-C中NSError **
的不同符号(inout error参数)。 Objective-C回调没有inout参数,因此无法传递错误。
您必须使用其他方法来处理错误。
一般情况下,Obj-C中的NSError **
或Swift中的throws
不能很好地处理异步方法,因为错误处理可以同步工作。
答案 2 :(得分:5)
因为throw是同步的,想要抛出的异步函数必须有一个抛出的内部闭包,例如:
func insertEventToDefaultCalendar(event :EKEvent, completion: (() throws -> Void) -> Void) {
let eventStore = EKEventStore()
switch EKEventStore.authorizationStatusForEntityType(.Event) {
case .Authorized:
do {
try insertEvent(eventStore, event: event)
completion { /*Success*/ }
} catch {
completion { throw CalendarEventError.Failed }
}
case .Denied:
completion { throw CalendarEventError.AccessDenied }
case .NotDetermined:
eventStore.requestAccessToEntityType(EKEntityType.Event, completion: { (granted, error) -> Void in
if granted {
let _ = try? self.insertEvent(eventStore, event: event)
completion { /*Success*/ }
} else {
completion { throw CalendarEventError.AccessDenied }
}
})
default:
break
}
}
然后,在呼叫站点,您可以像这样使用它:
insertEventToDefaultCalendar(EKEvent()) { response in
do {
try response()
// Success
}
catch {
// Error
print(error)
}
}
答案 3 :(得分:0)
您无法使用throw
启用功能,但返回状态或错误的closure
!
如果不清楚我可以提供一些代码。
答案 4 :(得分:0)
requestAccessToEntityType
以异步方式完成工作。最终运行完成处理程序后,您的函数已经返回。因此,不可能按照建议的方式从闭包中抛出错误。
您应该重构代码,以便授权部分与事件插入分开处理,并且只有在您知道授权状态符合预期/要求时才调用insertEventToDefaultCalendar
。
如果你真的想在一个函数中处理每个函数,你可以使用信号量(或类似的技术),以便异步代码部分在你的函数方面同步运行。
func insertEventToDefaultCalendar(event :EKEvent) throws {
var accessGranted: Bool = false
let eventStore = EKEventStore()
switch EKEventStore.authorizationStatusForEntityType(.Event) {
case .Authorized:
accessGranted = true
case .Denied, .Restricted:
accessGranted = false
case .NotDetermined:
let semaphore = dispatch_semaphore_create(0)
eventStore.requestAccessToEntityType(EKEntityType.Event, completion: { (granted, error) -> Void in
accessGranted = granted
dispatch_semaphore_signal(semaphore)
})
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}
if accessGranted {
do {
try insertEvent(eventStore, event: event)
} catch {
throw CalendarEventError.Failed
}
}
else {
throw CalendarEventError.AccessDenied
}
}