合并:如何在取消AnyCancelable时清理资源



概述:

  • 我有一个异步任务要从数据库中获取
  • 我已经为异步任务创建了一个Future(从数据库中获取(

问题:

  • 取消Future时如何执行自定义代码

目的:

  • 我希望在取消订阅时关闭数据库连接

例如,我想使用Combine重写这个辅助方法:

// Similar to https://developer.apple.com/documentation/coredata/nspersistentcontainer/1640564-performbackgroundtask
func withDatabaseFTSContext(block: @escaping (FMDatabase?) -> Void) {
queue.async {
guard let database = self.database else {
block(nil)
return
}
database.open()
let simpleTokenizer = FMSimpleTokenizer(locale: nil)
FMDatabase.registerTokenizer(simpleTokenizer, withKey: "simple")
database.installTokenizerModule()
block(database)
database.close()
}
}

我可以利用Combine重写这个方法,将FMDatabase作为发布者的参数返回吗?

我试图使用Combine,但它不起作用。数据库将在cancel()之前关闭

private func withDatabaseFTSContext() -> AnyPublisher<FMDatabase?, Never> {
return Future<FMDatabase?, Never> { promise in
self.queue.async {
guard let database = self.database else {
promise(.success(nil))
return
}
database.open()
let simpleTokenizer = FMSimpleTokenizer(locale: nil)
FMDatabase.registerTokenizer(simpleTokenizer, withKey: "simple")
database.installTokenizerModule()
promise(.success(database))
database.close() // When to close this database? Currently it will be closed before `cancel()`
}
}.eraseToAnyPublisher()
}

简单回答:没有一个回调可以触发到底层Future,您可以使用它来清理订阅服务器cancel上的内容。在Combine的设计中,这些功能是有意分离的,并且没有指向其发布者的参考链接。

(此外,Future在Combine世界中是一个棘手的数字,因为闭包是在创建时立即调用的,而不是在您有订阅时调用的(如果您想要,请将Future发布者封装在Deferred发布者中(。

话虽如此,为了解决根本问题,你可能想做的是重新定义你如何处理这个问题,将管理FMDB实例和发布数据的问题分开。在这种情况下,一种相当有用的模式是生成一个保存FMDB引用生存期的对象,并处理清理其deinit()上的资源。然后,您还可以拥有一个函数,该函数向发布服务器提供您从同一对象所需的任何内容,然后从语义上将请求的取消更改为仅取消获取数据库,而不是取消和清理数据库连接。

最新更新