【发布时间】:2022-09-26 16:38:14
【问题描述】:
我一直在使用找到的 CloudKitShare 示例代码 here 作为示例来帮助我为我的应用程序编写代码。我想使用在 BaseLocalCache 中找到的 performWriterBlock 和 performReaderBlockAndWait 使用 completionHandler 而不违反代码设计的目的,该目的侧重于线程安全。我在下面包含了与我的问题相关的 CloudKitShare 代码。我包括解释代码的 cmets。我写了 cmets 来识别哪个代码是我的。
如果可能的话,我希望能够使用转义的完成处理程序。使用转义的 completionHandler 是否仍然符合线程安全代码的原则,或者它是否以任何方式违反了此示例代码设计为线程安全的目的?如果我使用转义的完成处理程序,我需要考虑何时完成处理程序相对于使用 BaseLocalCache 执行块的实际执行功能范围之外的其他代码实际运行。一方面,我需要知道在方法执行时间和 BaseLocalCache 中的 operationQueue 实际执行代码块以及因此完成处理程序之间,我的项目中运行了哪些其他代码。
更新:
我补充说,我在最后编写的带有 \"// Trial: ...\" 标记的试用代码在代码时间期间会生成一条错误消息,上面写着 \"Type of expression is ambiguous without more context\"。当我删除内部花括号之间的代码并因此不发送任何代码作为 performReaderBlockAndWait(:) BaseLocalCache 方法,错误信息消失。我发现这是因为 performReaderBlockAndWait(:) 方法不处理我的试用代码 getServerChangeToken(completionHandler:) 的 completionHandler 参数。那是我难以弄清楚的部分。
class BaseLocalCache {
// A CloudKit task can be a single operation (CKDatabaseOperation)
// or multiple operations that you chain together.
// Provide an operation queue to get more flexibility on CloudKit operation management.
//
lazy var operationQueue: OperationQueue = OperationQueue()
// This sample ...
//
// This sample uses this dispatch queue to implement the following logics:
// - It serializes Writer blocks.
// - The reader block can be concurrent, but it needs to wait for the enqueued writer blocks to complete.
//
// To achieve that, this sample uses the following pattern:
// - Use a concurrent queue, cacheQueue.
// - Use cacheQueue.async(flags: .barrier) {} to execute writer blocks.
// - Use cacheQueue.sync(){} to execute reader blocks. The queue is concurrent,
// so reader blocks can be concurrent, unless any writer blocks are in the way.
// Note that Writer blocks block the reader, so they need to be as small as possible.
//
private lazy var cacheQueue: DispatchQueue = {
return DispatchQueue(label: \"LocalCache\", attributes: .concurrent)
}()
func performWriterBlock(_ writerBlock: @escaping () -> Void) {
cacheQueue.async(flags: .barrier) {
writerBlock()
}
}
func performReaderBlockAndWait<T>(_ readerBlock: () -> T) -> T {
return cacheQueue.sync {
return readerBlock()
}
}
}
final class TopicLocalCache: BaseLocalCache {
private var serverChangeToken: CKServerChangeToken?
func setServerChangeToken(newToken: CKServerChangeToken?) {
performWriterBlock { self.serverChangeToken = newToken }
}
func getServerChangeToken() -> CKServerChangeToken? {
return performReaderBlockAndWait { return self.serverChangeToken }
}
// Trial: How to use escaping completionHandler? with a performWriterBlock
func setServerChangeToken(newToken: CKServerChangeToken?, completionHandler: @escaping (Result<Void, Error>)->Void) {
performWriterBlock {
self.serverChangeToken = newToken
completionHandler(.success(Void()))
}
}
// Trial: How to use escaping completionHandler? with a performReaderBlockAndWait
func getServerChangeToken(completionHandler: (Result<CKServerChangeToken, Error>)->Void) {
performReaderBlockAndWait {
if let serverChangeToken = self.serverChangeToken {
completionHandler(.success(serverChangeToken))
} else {
completionHandler(.failure(NSError(domain: \"nil CKServerChangeToken\", code: 0)))
}
}
}
}
标签: ios swift concurrency thread-safety swift-concurrency