Swift @ gestionnaire d'échappement et D'achèvement

[Swift]

Salut, j'essaie de comprendre plus précisément la 'fermeture' de Swift.

, Mais @escaping et Completion Handler sont trop difficiles à comprendre

J'ai cherché beaucoup de messages Swift et de documents officiels, mais je sentais que ce n'était toujours pas suffisant.

C'est L'exemple de code des documents officiels

var completionHandlers: [()->Void] = []

func someFunctionWithEscapingClosure(completionHandler: @escaping ()->Void){
    completionHandlers.append(completionHandler)
}
func someFunctionWithNoneescapingClosure(closure: ()->Void){
    closure()
}

class SomeClass{
    var x:Int = 10
    func doSomething(){
        someFunctionWithEscapingClosure {
            self.x = 100
            //not excute yet
        }
        someFunctionWithNoneescapingClosure {
            x = 200
        }
    }
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)

completionHandlers.first?() 
print(instance.x)

J'ai entendu dire qu'il y a deux façons et raisons d'utiliser @escaping

Le premier est pour stocker une fermeture, le second est pour le fonctionnement asynchrone but.

Voici mes questions:

Tout d'abord, si doSomething s'exécute alors someFunctionWithEscapingClosure s'exécutera avec le paramètre closure et cette fermeture sera enregistrée dans un tableau de variables globales.

, je pense que la fermeture est {self.x = 100}

Comment self dans {self.x = 100} qui est enregistré dans la variable globale completionHandlers peut se connecter à instance cet objet de SomeClass?

Deuxièmement, je comprends someFunctionWithEscapingClosure comme ceci.

Pour stocker la fermeture de variable locale completionHandler pour variable globale ' completionHandlers we using @ escaping` mot-clé!

Sans @escaping mot-clé someFunctionWithEscapingClosure retourne, variable locale completionHandler va supprimer de la mémoire

@escaping est de garder cette fermeture dans la mémoire

Est-ce vrai?

Enfin, je m'interroge sur l'existence de cette grammaire.

C'est peut-être une question très rudimentaire.

Si nous voulons qu'une fonction s'exécute après une fonction spécifique. Pourquoi ne pas appeler une fonction après un appel de fonction spécifique?

Quelles sont les différences entre l'utilisation du modèle ci-dessus et l'utilisation d'une fonction de rappel d'échappement?

Merci d'avoir lu de longues questions et désolé pour Je ne suis pas natif

41
demandé sur Dung Ta 2017-09-15 21:29:01

2 réponses

Tout d'abord, je veux dire "très bonne Question:)"

Gestionnaire D'Achèvement :

Supposons que l'utilisateur met à jour une application tout en l'utilisant. Vous voulez certainement informer l'utilisateur quand il est fait. Vous pouvez afficher une boîte qui dit: "Félicitations, vous pouvez maintenant profiter pleinement de!"

Alors, comment exécutez-vous un bloc de code uniquement après le téléchargement? En outre, comment animez-vous Certains objets uniquement après qu'un contrôleur de vue a été déplacé vers le la prochaine? Eh bien, nous allons découvrir comment concevoir un comme un boss. Sur la base de ma liste de vocabulaire expansive, les gestionnaires d'achèvement représentent

Faire des trucs quand les choses ont été faites

Pour plus de détails, veuillez visiter ce blog.

Ce lien me donne une clarté complète sur les gestionnaires d'achèvement (du point de vue du développeur, il définit exactement ce que nous devons comprendre).

@échapper fermetures:

Lorsque vous êtes passer la fermeture dans les arguments d'une fonction, l'utiliser après l'exécution du corps de la fonction et renvoyer le compilateur. Lorsque la fonction se termine, la portée de la fermeture passée existe et existe en mémoire, jusqu'à ce que la fermeture soit exécutée.

Il existe plusieurs façons d'échapper à la fermeture dans la fonction contenant:

  • Stockage: lorsque vous devez stocker la fermeture dans la variable globale, la propriété ou tout autre stockage existant dans la mémoire passée de la la fonction d'appel est exécutée et renvoie le compilateur.

  • Exécution asynchrone: lorsque vous exécutez la fermeture de manière asynchrone sur la file d'attente des envois, la file d'attente conservera la fermeture en mémoire pour vous, peut être utilisée à l'avenir. Dans ce cas, vous ne savez pas quand la fermeture sera exécutée.

Lorsque vous essayez d'utiliser la fermeture dans ces scénarios, la Swift compilateur affiche l'erreur:

erreur capture d'écran

Pour plus de clarté sur ce sujet, vous peut consulter Ce post sur Medium .

J'espère que vous obtiendrez une bonne compréhension de ce lien.

Si vous avez des questions (mais assurez-vous de lire ce lien, ligne par ligne, d'abord; c'est très bien expliqué), alors n'hésitez pas à partager votre commentaire.

Merci, continuez à poster si cette réponse doit être mise à jour

56
répondu Shobhakar Tiwari 2018-07-06 06:20:47

Voici une petite classe d'exemples que j'utilise pour me rappeler comment @échapper œuvres.

class EscapingExamples: NSObject {

    var closure: (() -> Void)?

    func storageExample(with completion: (() -> Void)) {
        //This will produce a compile time error because `closure` is outside the scope of this
        //function - it's a class-instance level variable - and so it could be called by any other method at
        //any time, even after this function has completed.  We need to tell `completion` that it may remain in memory, i.e. `escape` the scope of this
        //function.
        closure = completion
        //Run some function that may call `closure` at some point, but not necessary for the error to show up.
        //runOperation()
    }

    func asyncExample(with completion: (() -> Void)) {
        //This will produce a compile time error because the completion closure may be called at any time
        //due to the async nature of the call which preceeds/encloses it.  We need to tell `completion` that it should
        //stay in memory, i.e.`escape` the scope of this function.
        DispatchQueue.global().async {
            completion()
        }
    }

    func asyncExample2(with completion: (() -> Void)) {
        //The same as the above method - the compiler sees the `@escaping` nature of the
        //closure required by `anotherThing()` and tells us we need to allow our own completion
        //closure to be @escaping too.  `anotherThing`'s completion block will be retained in memory until
        //it is executed, so our completion closure must explicitely do the same.
        runAsyncTask {
            completion()
        }
    }





    func runAsyncTask(completion: @escaping (() -> Void)) {
        DispatchQueue.global().async {
            completion()
        }
    }

}
6
répondu JamesK 2018-08-02 09:21:40