实现重新抛出函数

Implementing a rethrowing function

我正在为 CoreData 实现一个辅助方法

public func doInMain(_ block: (NSManagedObjectContext) -> Void) {
    guard let context = mainQueueContext else { return }
    context.performAndWait({
        block(context)
    })
}

效果很好,可以这样调用:

CoreDataManager().doInMain { moc in
    // do your fetch request with managed object context
}

但是当我想在doInMain块中尝试错误时很烦人,因为它不能被调用函数重新抛出。既然bloc是nonescaping,就应该做。

所以我补充说:

public func doInMain(_ block: (NSManagedObjectContext) throws -> Void) rethrows {
    guard let context = mainQueueContext else { return }
    context.performAndWait({
        try block(context)
    })
}

但是NSManagedObjectContext.performAndWait不会重新抛出错误,所以不会编译。

它试过这个:

public func doInMain(_ block: (NSManagedObjectContext) throws -> Void) rethrows {
    guard let context = mainQueueContext else { return }
    var thrownError: Error?
    context.performAndWait({
        do { try block(context) }
        catch { thrownError = error }
    })
    if let error = thrownError {
        throw error
    }
}

但是现在编译器说 A function declared 'rethrows' may only throw if its parameter does

我搞砸了吗?有解决方法吗?

谢谢

不完全理想,但一种选择是只编写两个重载——一个采用不抛出闭包且自身不抛出的闭包,另一个采用抛出闭包且自身抛出。

例如:

public func doInMain(_ block: (NSManagedObjectContext) -> Void) {
  guard let context = mainQueueContext else { return }
  context.performAndWait {
    block(context)
  }
}

public func doInMain(_ block: (NSManagedObjectContext) throws -> Void) throws {
  guard let context = mainQueueContext else { return }
  var thrownError: Error?
  context.performAndWait {
    do {
      try block(context)
    } catch {
      thrownError = error
    }
  }
  if let error = thrownError {
    throw error
  }
}

请记住,如果需要,您始终可以根据抛出重载来实现非抛出重载:

public func doInMain(_ block: (NSManagedObjectContext) -> Void) {
  let fn = doInMain as ((NSManagedObjectContext) throws -> Void) throws -> Void
  try! fn(block)
}

您应该能够像使用单个重新抛出重载一样使用这两个重载。

iOS 15 中有新的 performAndWait 方法可用,它允许重新抛出。

func performAndWait<T>(_ block: () throws -> T) rethrows -> T