即使在主方法中我的操作尚未完成之前,也会触发完成块

时间:2019-10-08 04:38:30

标签: ios swift firebase-authentication nsoperationqueue nsoperation

我正在尝试使用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

        }
    }

}

1 个答案:

答案 0 :(得分:1)

问题是您的操作正在启动一个异步进程,但是该操作是在启动异步任务时完成的,而不是在异步任务完成时完成的。

您需要执行与“并发”操作相关的KVO,如the documentation所述:

  

如果要创建并发操作,则至少需要覆盖以下方法和属性:

     
      
  • start()
  •   
  • isAsynchronous
  •   
  • isExecuting
  •   
  • isFinished
  •   
     

在并发操作中,您的start()方法负责以异步方式启动该操作。无论是生成线程还是调用异步函数,都可以通过此方法进行。开始操作后,您的start()方法还应更新isExecuting属性所报告的操作的执行状态。您可以通过发送isExecuting密钥路径的KVO通知来完成此操作,该通知使感兴趣的客户端知道该操作正在运行。您的isExecuting属性还必须以线程安全的方式提供状态。

     

在完成或取消其任务后,您的并发操作对象必须同时为isExecutingisFinished键路径生成KVO通知,以标记操作状态的最终改变。 (在取消的情况下,即使操作没有完全完成其任务,更新isFinished密钥路径仍然很重要。排队的操作必须报告它们已完成,然后才能将其从队列中删除。 )除了生成KVO通知之外,您对isExecutingisFinished属性的替代还应根据操作状态继续报告准确的值。

现在所有这些听起来都很毛茸茸,但实际上还算不错。一种方法是编写一个基本操作类,它处理所有这些KVO内容,以及this this answer outlines one example implementation

然后,您可以改为继承AsynchronousOperation的子类,并确保在完成任务后调用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 else {
                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的类,就可以对其进行子类化,并且只需编写很少的代码即可编写自己的并发操作。