我正在Swift4中使用名为“ YapDatabase”的Object-C框架开发iOS应用。类'YapDatabaseConnection'中有一个带有这样一个块的Object-C函数:
setdiff(y, x)
我以这种方式使用该功能:
- (void)readWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block;
我认为在声明“ events”参数后将立即执行关闭。实际上,闭包不会在结果返回之前执行。为了查找原因,我打开了Xcode生成的名为“ YapDatabaseConnection.h(Interface)”的文件(使用cmd + shift + o),发现该函数已通过以下方式转换为Swift:
static func readNovelIds() -> [String]? {
let account = XFAccountManager.share().account
var events: [XFNovelClickEvent]?
OTRDatabaseManager.shared.readOnlyDatabaseConnection?.read({ (transaction) in
events = XFNovelClickEvent.allNovelClickEvents(accountId: account.uniqueId, transaction: transaction)
})
guard let clickEvents = events else {
return nil
}
let readNovelsIds = clickEvents.map {
$0.bookId ?? ""
}
return readNovelsIds
}
那么,如何以@noescap方式使用此功能?
答案 0 :(得分:0)
作为调用者,执行闭包时不能更改。这取决于read()
函数。如果控制该函数,则需要对其进行修改以立即调用闭包。如果您无法控制它,那么您将无法修改其行为。
您可以使用Waiting until the task finishes中所述的DispatchGroup
将异步呼叫转换为同步呼叫。但是,您不能在主队列上进行数据库调用。您可能会崩溃该应用程序。通常,在这种情况下,您应该只使用异步调用(即,使readNovelIds
也异步并采用完成处理程序)。
答案 1 :(得分:0)
Xcode将Objective-C块桥接为@escaping
的原因是因为该块可能在函数返回后执行。
由于您不拥有YapDatabase
,因此无法修改源代码以使其不转义,因此您可能希望使readNovelIds
函数将闭包作为参数并传递给通过闭包返回值。
static func readNovelIds(resultHandler: @escaping ([String]?) -> ()) {
let account = XFAccountManager.share().account
var events: [XFNovelClickEvent]?
OTRDatabaseManager.shared.readOnlyDatabaseConnection?.read({ (transaction) in
events = XFNovelClickEvent.allNovelClickEvents(accountId: account.uniqueId, transaction: transaction)
if let clickEvents = events {
let readNovelsIds = clickEvents.map {
$0.bookId ?? ""
}
resultHandler(readNovelsIds)
}
resultHandler(nil)
})
}
答案 2 :(得分:0)
如果该方法实际上是同步的(即它将不允许该块转义其上下文),则应该使用NS_NOESCAPE装饰Objective C标头方法。查看文档(确实说它是同步的)和实现,应该用这种方式对其进行注释。
- (void)readWithBlock:(void (NS_NOESCAPE ^)(YapDatabaseReadTransaction *transaction))block;
我认为,这应该允许Swift接口导入器添加@noescaping声明。您可能应该在YapDatabase项目上提交错误请求;他们可以在那里更改它。