Tengo varias etiquetas, y quiero que se animen una tras otra. Así que he creado un controlador de finalización que debería ejecutar la siguiente tarea una vez que la anterior haya finalizado. (firstTask -> secondTask -> thirdTask -> 4thTask al final).

Pero por alguna razón, todas las animaciones se ejecutan al mismo tiempo. ¿Qué estoy haciendo mal?

func firstTask(completion: (_ success: Bool) -> Void) {
    UIView.transition(with: labelOne,
         duration: 1,
          options: .transitionCrossDissolve,
       animations: { [weak self] in
           self?.labelOne.text = arrayOne[RandomWordGenOne]
    }, completion: nil)
    completion(true)
}

// two more tasks in between just like the firstTask func …

func fourthTask() {
    UIView.transition(with: labelFour,
         duration: 1,
          options: .transitionCrossDissolve,
       animations: { [weak self] in
           self?.labelFour.text = arrayFour[RandomWordGenFour]
    }, completion: nil)
}

El controlador de finalización:

firstTask { (success) -> Void in
    if success {
        secondTask { (success2) -> Void in
            if success2 {
                thirdTask { (success3) -> Void in
                    if success3 {
                        fourthTask()
                    }
                }
            }
        }
    }
}
1
publicjulian 22 jun. 2020 a las 17:16

4 respuestas

La mejor respuesta

Debe ejecutar su bloque de finalización, cuando finalice la animación, que ocurre al completar el bloque de animación.

func firstTask(completion: @escaping ((_ success: Bool) -> Void)) {
    UIView.transition(with: randomOne, duration: 1, options: .transitionCrossDissolve, animations: {
        self?.randomOne.text = location[RandomWordGenOne]
    }) { (finished) in
        completion(true)
    }
}
1
Reinier Melian 22 jun. 2020 a las 14:37

Es porque no está escribiendo el bloque completion en el controlador de finalización. Y necesita usar cierres de escape para lograr eso. Aquí está el código actualizado.

   func firstTask(completion: @escaping ((_ success: Bool) -> Void)) {
        // The animation. The others are all basically the same.
        UIView.transition(with: randomOne,
             duration: 1,
              options: .transitionCrossDissolve,
           animations: { [weak self] in
               self?.randomOne.text = location[RandomWordGenOne]
        }, completion: completion)
        //self.randomOne.animate(newText: location[RandomWordGenOne], characterDelay: 0.05)
 
    }
    
    func secondTask(completion: @escaping ((_ success: Bool) -> Void)) {
        UIView.transition(with: dash,
             duration: 1,
              options: .transitionCrossDissolve,
           animations: { [weak self] in
               self?.dash.text = " – "
        }, completion: completion)
        //self.dash.animate(newText: " – ", characterDelay: 0.05)
    }
    
    func thirdTask(completion: @escaping ((_ success: Bool) -> Void)) {
        UIView.transition(with: randomTwo,
             duration: 1,
              options: .transitionCrossDissolve,
           animations: { [weak self] in
               self?.randomTwo.text = time[RandomWordGenTwo]
        }, completion: completion)
        //self.randomTwo.animate(newText: time[RandomWordGenTwo], characterDelay: 0.05)

    }
    
    func fourthTask() {
        UIView.transition(with: randomThree,
             duration: 1,
              options: .transitionCrossDissolve,
           animations: { [weak self] in
               self?.randomThree.text = text[RandomWordGenThree]
        }, completion: nil)
        //self.randomThree.animate(newText: text[RandomWordGenThree], characterDelay: 0.05)
    }

   

Y luego actualice la llamada al método como se muestra a continuación

firstTask { (success) in
        if success {
            secondTask { (success2) in
               if success2 {
                    thirdTask { (success3) in
                        if success3 {
                            fourthTask()
                        }
                    }
                }
            }
        }
    }
0
Rupesh 22 jun. 2020 a las 14:36

Cuando usa un controlador de finalización, debe asignar la variable donde escribe la función para que pueda usarse cuando la llame. Por ejemplo:

    func changeLabel(completion: (Bool) -> Void)) {
        //insert whatever you want the function do 
        if (whateverYouWantedToHappenCompletes) {
           completion(true)
        } else {
           completion(false)
        }
    }
    
    changeLabel { (success) in 
       //now you can use the success parameter
    }

Si no puede resolver esto, busque algunos videos sobre cómo usar los controladores de finalización, u otra opción válida es usar el controlador de finalización incorporado en UIView.animate

-2
Nick Viscomi 22 jun. 2020 a las 14:33

Tienes que agregar @escaping en la firma de la función. Aquí hay un ejemplo

   func getSumOf(array:[Int], handler: @escaping ((Int)->Void)) {
               // add your code here
}
-1
Moumen Alisawe 22 jun. 2020 a las 14:29