Un souci avec une animation qui ne marche qu'à moitié... ou comment GrandCentralDispatch m'a sauvé !

Bonjour à tous,

j’ai un souci avec une animation qui ne se lance pas quand je le voudrais : elle disparait bien (animOut) mais n’est pas apparue avant… et même, quand je checke la console, c’est pire : elle tente d’apparaître après avoir disparue apparemment :-/

Voici mon code expurgé :

//
//  TabDeclaMensuellesViewController.swift
//  IntermittentsTV
//
//  Created by 27|28 réalisation(s) on 26/06/2017.
//  Copyright © 2017 27|28 réalisation(s). All rights reserved.
//

import UIKit
import RealmSwift
import SwifterSwift
import StoreKit

class TabDeclaMensuellesViewController: UIViewController  {

// VARIABLES

(...)

var effect:UIVisualEffect!


// INITIAL FUNCTIONS
override func viewDidLoad() {

(...)

    effect = visualEffectView.effect
    visualEffectView.effect = nil
}

(...)

// OUTLETS & ACTIONS

(...)

@IBAction func saveBrut(_ sender: Any) {

(...)

    waitViewOn()
    waitLabel.text = "Calcul des franchises"
    updateFranchise()
    waitLabel.text = "Calcul des reports"
    updateReport()
    waitLabel.text = "Calcul des indemnités"
    updateIndemnites()
    waitViewOff()

(...)

   }


(...)


@IBOutlet var waitView: UIView!
@IBOutlet weak var waitLabel: UILabel!
@IBOutlet weak var waitAnim: UIActivityIndicatorView!
@IBOutlet weak var waitProgress: UIProgressView!

@IBOutlet weak var visualEffectView: UIVisualEffectView!

// UNWIND

@IBAction func unwindSegueSaisieMois (_ sender: UIStoryboardSegue){
}

// FUNCTIONS


(...)


func waitViewOn() {
    print("DEBUG ANIM : waitView IN")
    
    let fullWidth = self.view.width
    waitView.width = fullWidth * 0.8
    waitView.height = fullWidth * 0.4
    waitView.layer.cornerRadius = 10
    waitView.center = self.view.center
    
    waitView.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
    
    waitView.alpha = 0
    
    waitProgress.progress = 0
    waitAnim.startAnimating()
    waitLabel.text = "Sauvegarde"
    
    self.view.addSubview(waitView)
    
    UIView.animate(withDuration: 0.4, animations: {
        self.visualEffectView.effect = self.effect
        self.waitView.alpha = 1
        self.waitView.transform = CGAffineTransform.identity
    }) { (success:Bool) in
        print("DEBUG ANIM : waitView IN done")
    }
    
    print("DEBUG ANIM : waitView IN end")
}

func waitViewOff() {
    print("DEBUG ANIM : waitView OUT")

    waitAnim.stopAnimating()
    waitLabel.text = "FINI !"
    
    UIView.animate(withDuration: 0.3, animations: {
        self.waitView.alpha = 0
        self.visualEffectView.effect = nil
    }) { (success:Bool) in
        self.waitView.removeFromSuperview()
        print("DEBUG ANIM : waitView OUT done")            
    }
    
    print("DEBUG ANIM : waitView OUT end")
}

func updateMois() {
    
 
(...)

}

func lireLesUserDefaults() {
 
(...)

}

func sauverDansUserDefaults() {

(...)

}

func updateReport() {
 
(...)

    for i in 0...11 {
        let curseur = i + 1
        let borne = 11 + 1
        waitProgress.progress = Float(curseur / borne)
 
(...)

        }
    }
}

func updateFranchise() {

(...)

    for i in moisChoisi...12 {
        let curseur = i + 1 - moisChoisi
        let borne = 12 + 1 - moisChoisi
        waitProgress.progress = Float(curseur / borne)

(...)

    }
}

func updateIndemnites() {

(...)

    for i in moisChoisi...12 {
        let curseur = i + 1 - moisChoisi
        let borne = 12 + 1 - moisChoisi
        waitProgress.progress = Float(curseur / borne)

(...)

    }
}
}

Quelqu’un saurait-il me dire ce qui coince ?

Voici le retour en console :

DEBUG ANIM : waitView IN
DEBUG ANIM : waitView IN end
DEBUG ANIM : waitView OUT
DEBUG ANIM : waitView OUT end
DEBUG ANIM : waitView OUT done
DEBUG ANIM : waitView IN done

… énervant :wink:

Merci d’avance à vous !! :slight_smile:

… et j’ai tenté de solutionner mon problème en utilisant GrandCentralDispatch.

waitViewOn()
_dispatchQueue.async {
    self.updateFranchise()
    self.updateReport()
    self.updateIndemnites()
    self.waitViewOff()
}

Dans un premier temps, ça fonctionne : j’ai bien mon animation d’entrée mais il semble que Realm n’aime pas trop qu’on l’utilise depuis un thread secondaire : mes manips de dBase (qui sont l’essentiel des tâches des 3 fonctions update() incluses dans le thread secondaire) que je voulais faire en tâche de fond ne sont donc pas possible, et je reviens donc quasiment à mon point de départ…

IntermittentsTV[57619:13563050] *** Terminating app due to uncaught exception 'RLMException', reason: 'Realm accessed from incorrect thread.'

Après essais et lectures assidues de ma console, j’ai compris qu’il fallait que je re-crée un royaume dans le thread parallèle :

    let realm2 = try! Realm()

… et là ça fonctionne ! :slight_smile:

Au final, c’est donc GrandCentralDispatch qui m’a sauvé…
Je ne sais pas trop si ça se justifie de laisser ce fil, qui est surtout un monologue :wink: mais si ça peut aider quelqu’un ? Je laisse Maxime juger de la pertinence de laisser cela à dispo…

Salut Alexis,

le problème venait du fait que tu programmes en même temps l’apparition et la disparition. Chronologiquement tu les as bien lancé dans l’ordre mais l’animation IN n’avait probablement pas encore commencé quand tu as lancé l’animation OUT. Comme ton animation IN a une durée de 0.4s et l’animation OUT a une durée de 0.3s, tu vois le log de fin qui arrive dans le mauvais ordre (celle du OUT se termine avant celle du in).
Ta solution de GCD marche car tu programmes le OUT plus tard avec le async.
Une autre solution aurait été d’utiliser ta closure de fin d’animation IN (celle où tu fais print("DEBUG ANIM : waitView IN done") pour déclencher l’animation OUT.