【问题标题】:Implementing a rethrowing function实现重新抛出功能
【发布时间】:2018-12-26 09:43:38
【问题描述】:

我正在为 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: @escaping (NSManagedObjectContext?, Error?) -> Void) { guard let context = mainQueueContext else { return } context.performAndWait({ block(context, nil) }) }
  • 因为我不希望我的方法是@esccapingperformAndWait 不是,所以我的方法应该被编译器认为是同步的。它确实简化了使用它

标签: swift error-handling try-catch throw


【解决方案1】:

不完全理想,但一种选择是只编写两个重载——一个接受一个不抛出的闭包并且它自己不抛出,另一个接受一个抛出的闭包并且它自己抛出。

例如:

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)
}

您应该能够以与单个重新抛出重载几乎相同的方式使用这两个重载。

【讨论】:

  • 不完全理想,但它可以完成工作。由于performAndWait 不要重新抛出我认为没有更好的解决方案。谢谢,我不知道我们可以通过改变方法抛出错误的方式来覆盖。
【解决方案2】:

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

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

【讨论】:

  • 感谢苹果,终于!
猜你喜欢
  • 2022-11-02
  • 2020-01-05
  • 1970-01-01
  • 2021-03-26
  • 2020-03-03
  • 2011-02-26
  • 1970-01-01
  • 2014-02-13
  • 2012-10-24
相关资源
最近更新 更多