Блок завершения запускается еще до того, как моя операция завершается в основном методе - PullRequest
3 голосов
/ 08 октября 2019

Я пытаюсь создать пользователя в firebase, используя OperationQueue и Operation. Я поместил вызов 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 Ответ

1 голос
/ 08 октября 2019

Проблема заключается в том, что ваша операция инициирует асинхронный процесс, но операция завершается при запуске асинхронной задачи, а не при завершении асинхронной задачи.

Необходимо выполнить KVO, связанный с «одновременным”, Как описано в документации :

Если вы создаете параллельную операцию, вам необходимо как минимум переопределить следующие методы и свойства:

  • start()
  • isAsynchronous
  • isExecuting
  • isFinished

В параллельной операции ваш *Метод 1024 * отвечает за запуск операции в асинхронном режиме. Независимо от того, порождаете ли вы поток или вызываете асинхронную функцию, вы делаете это из этого метода. После запуска операции ваш метод start() также должен обновить состояние выполнения операции, сообщаемое свойством isExecuting. Вы делаете это, отправляя уведомления KVO по ключевому пути isExecuting, который позволяет заинтересованным клиентам узнать, что операция сейчас выполняется. Ваше свойство isExecuting также должно предоставлять состояние в поточно-ориентированном режиме.

После завершения или отмены своей задачи объект параллельной операции должен генерировать уведомления KVO для ключа isExecuting и isFinished. пути, чтобы отметить окончательное изменение состояния для вашей операции. (В случае отмены все еще важно обновить путь ключа isFinished, даже если операция не полностью завершила свою задачу. Операции в очереди должны сообщить о том, что они завершены, прежде чем их можно будет удалить из очереди.) ВВ дополнение к генерации уведомлений KVO ваши переопределения свойств isExecuting и isFinished также должны продолжать сообщать точные значения, основанные на состоянии вашей операции.

Теперь все это звучит довольно странно,но это на самом деле не так уж и плохо. Один из способов - написать базовый класс операций, который позаботится обо всех этих вещах KVO, и в этом ответе приведен пример реализации .

Тогда вы можете вместо этого создать подкласс 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, вы можете создать его подкласс и написать свои собственные параллельные операции с очень небольшими изменениями в вашем коде.

...