我正在尝试使用OperationQueue和Operation在firebase中创建用户。我在操作main方法中放置了Firebase Auth调用。即使在Firebase注册过程成功之前,也会触发操作的完成块。
RegistrationViewModal.swift
//This is operation initialization
let operationQueues = OperationQueues()
let registrationRecord = RegistrationRecord(user: self.user!, encryptedData: self.fireBaseAuthCompliance)
let userRegistrationOperation = UserRegistrationOperation(registrationRecord: registrationRecord)
userRegistrationOperation.completionBlock = {
//I am expecting this completion block will be called only when my firebase invocation in main() method is finished
DispatchQueue.main.async {
//Since this block is getting triggered even before completion, the //value is returning as null
self.user?.uid = userRegistrationOperation.registrationRecord.user.uid
}
}
operationQueues.userRegistrationQueue.addOperation(userRegistrationOperation)
UserRegistrationOperation.swift
class OperationQueues {
lazy var userRegistrationQueue: OperationQueue = {
var queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
queue.name = "User registration queue"
return queue
}()
}
class UserRegistrationOperation: Operation {
var registrationRecord: RegistrationRecord
init(registrationRecord: RegistrationRecord) {
self.registrationRecord = registrationRecord
}
override func main() {
guard !isCancelled else { return }
self.registrationRecord.state = RegistrationStatus.pending
//Firebase invocation to create a user in Firebase Auth
Auth.auth().createUser(withEmail: self.registrationRecord.user.userEmail, password: self.registrationRecord.encryptedData){ [weak self](result, error) in
if error != nil {
print("Error occured while user registration process")
self?.registrationRecord.state = RegistrationStatus.failed
return
}
self?.registrationRecord.user.uid = result?.user.uid
self?.registrationRecord.state = RegistrationStatus.processed
}
}
}
问题是您的操作正在启动一个异步过程,但是该操作在启动异步任务时完成,而不是在异步任务完成时完成。
您需要执行与“并发”操作相关的KVO,如the documentation中所述:
如果要创建并发操作,则至少需要重写以下方法和属性:
start()
isAsynchronous
isExecuting
isFinished
在并发操作中,您的
start()
方法负责以异步方式启动该操作。无论是生成线程还是调用异步函数,都可以通过此方法进行。在开始操作时,您的start()
方法还应更新isExecuting
属性报告的操作的执行状态。您可以通过发送isExecuting
键路径的KVO通知来执行此操作,该通知使感兴趣的客户端知道该操作正在运行。您的isExecuting属性还必须以线程安全的方式提供状态。[完成或取消其任务后,您的并发操作对象必须为
isExecuting
和isFinished
键路径生成KVO通知,以标记操作状态的最终改变。 (在取消的情况下,更新isFinished
键路径仍然很重要,即使该操作没有完全完成其任务。排队的操作也必须报告它们已完成,然后才能将其从队列中删除。)除了生成KVO通知之外,您对isExecuting
和isFinished
属性的替代也应继续根据操作状态报告准确的值。
现在所有这些听起来都很毛茸茸,但实际上还不错。一种方法是编写一个基本的操作类来处理所有这些KVO内容this this answer outlines。
然后,您可以将AsynchronousOperation
子类化(例如,如何实现的一个例子是defined in that answer),并确保在完成任务时调用finish
(或触发isFinished
KVO的任何方法:] >
class UserRegistrationOperation: AsynchronousOperation { var registrationRecord: RegistrationRecord init(registrationRecord: RegistrationRecord) { self.registrationRecord = registrationRecord super.init() // whenever you subclass, remember to call `super` } override func main() { self.registrationRecord.state = .pending //Firebase invocation to create a user in Firebase Auth Auth.auth().createUser(withEmail: registrationRecord.user.userEmail, password:registrationRecord.encryptedData){ [weak self] result, error in defer { self?.finish() } // make sure to call `finish` regardless of how we leave this closure guard let result = result, error = nil { print("Error occured while user registration process") self?.registrationRecord.state = .failed return } self?.registrationRecord.user.uid = result.user.uid self?.registrationRecord.state = .processed } } }
[实现
AsynchronousOperation
类的方法有很多,this只是一个示例。但是一旦有了一个很好地封装了并发操作KVO的类,就可以对其进行子类化,并且您只需很少改动代码就可以实现并发操作行为。