method functions closure swift escaping closures

functions - Swift @escaping and Completion Handler



swift functions (4)

Estoy tratando de entender ''Cierre'' de Swift con mayor precisión.

Pero @escaping y Completion Handler son demasiado difíciles de entender.

Busqué en muchas publicaciones y documentos oficiales de Swift, pero sentí que aún no era suficiente.

Este es el ejemplo de código de documentos oficiales

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)

Escuché que hay dos formas y razones para usar @escaping

El primero es para almacenar un cierre, el segundo es para fines operativos asíncronos.

Las siguientes son mis preguntas :

Primero, si se ejecuta someFunctionWithEscapingClosure , someFunctionWithEscapingClosure se ejecutará con el parámetro de cierre y ese cierre se guardará en una matriz variable global.

Creo que el cierre es {self.x = 100}

¿Cómo self en {self.x = 100} que se guardó en la variable global completionHandlers puede conectarse a la instance ese objeto de SomeClass ?

En segundo lugar, entiendo someFunctionWithEscapingClosure esta manera.

¡Para almacenar la variable de cierre local completionHandler en la variable global ''completeHandlers'', we using palabra clave @ escape`!

sin la palabra clave someFunctionWithEscapingClosure , se devuelve someFunctionWithEscapingClosure , la variable local completionHandler se eliminará de la memoria

@escaping es mantener ese cierre en la memoria

¿Es esto correcto?

Por último, me pregunto acerca de la existencia de esta gramática.

Tal vez esta es una pregunta muy rudimentaria.

Si queremos que alguna función se ejecute después de alguna función específica. ¿Por qué no simplemente llamamos a alguna función después de una llamada a una función específica?

¿Cuáles son las diferencias entre usar el patrón anterior y usar una función de devolución de llamada de escape?


Aquí hay una pequeña clase de ejemplos que uso para recordarme cómo funciona @escaping.

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 precedes/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 `runAsyncTask()` and tells us we need to allow our own completion //closure to be @escaping too. `runAsyncTask`''s completion block will be retained in memory until //it is executed, so our completion closure must explicitly do the same. runAsyncTask { completion() } } func runAsyncTask(completion: @escaping (() -> Void)) { DispatchQueue.global().async { completion() } } }


En primer lugar, quiero decir "Muy buena pregunta :)"

Controlador de finalización:

Suponga que el usuario está actualizando una aplicación mientras la usa. Definitivamente desea notificar al usuario cuando haya terminado. Es posible que desee abrir un cuadro que diga: "¡Felicitaciones, ahora, puede disfrutarlo plenamente!"

Entonces, ¿cómo ejecuta un bloque de código solo después de que se haya completado la descarga? Además, ¿cómo anima ciertos objetos solo después de que un controlador de vista se haya movido al siguiente? Bueno, vamos a descubrir cómo diseñar uno como un jefe. Según mi extensa lista de vocabulario, los controladores de finalización representan

Haz cosas cuando las cosas se hayan hecho

Para más detalles, visite esta publicación de blog .

Este enlace me da una claridad completa sobre los controladores de finalización (desde el punto de vista del desarrollador, define exactamente lo que necesitamos entender).

@ cierres de escape:

Cuando pasa el cierre en los argumentos de una función, lo usa después de que el cuerpo de la función se ejecuta y devuelve el compilador. Cuando finaliza la función, el alcance del cierre pasado existe y tiene existencia en la memoria, hasta que se ejecuta el cierre.

Hay varias formas de escapar del cierre en la función de contención:

  • Almacenamiento: cuando necesita almacenar el cierre en la variable global, la propiedad o cualquier otro almacenamiento que exista en la memoria anterior a la función de llamada se ejecuta y devuelve el compilador.

  • Ejecución asincrónica: cuando está ejecutando el cierre de forma asincrónica en la cola de despacho, la cola retendrá el cierre en la memoria, puede usarse en el futuro. En este caso, no tiene idea de cuándo se ejecutará el cierre.

Cuando intente utilizar el cierre en estos escenarios, el compilador Swift mostrará el error:

Para obtener más claridad sobre este tema, puede consultar esta publicación en Medium .

Espero que entiendan bien este enlace.

Si aún tiene alguna pregunta (pero asegúrese de leer este enlace línea por línea primero; está muy bien explicado), no dude en compartir su comentario.

Gracias, sigue publicando si esta respuesta necesita actualizarse


Función

Usted define una función con la palabra clave func . Las funciones pueden tomar muchos parámetros y devolver ninguno, uno o varios parámetros

Cierre

Los cierres son bloques de funcionalidad autónomos que se pueden pasar y usar en su código. Los cierres en Swift son similares a los bloques en C y Objective-C y a lambdas en otros lenguajes de programación.

Funciones y cierres y son tipos de primera clase en swift:

  • asignar una función / cierre a una variable local
  • pasar una función / cierre como argumento
  • devolver una función / cierre

Cierre de escape versus cierre sin escape

  • Un non-escaping closure @noescape es un cierre que se llama dentro de la función a la que se pasó, es decir, antes de que regrese.

    Un buen ejemplo de non-escaping closure es la sort function de sort function de la matriz, como sorted(by: (Element, Element) -> Bool) . El cierre toma dos parámetros y devuelve un Bool que determina un resultado de la función de clasificación. Se llama al cierre durante la ejecución de un cálculo de clasificación.

    * @noescape era un atributo en swift 2 . Esto está en desuso de swift 3 . The swift 3 . The attribute is applied by default in @noescape attribute is applied by default in Swift 3 . Because closures are by default . Because closures are by default no se escapan . Because closures are by default in Swift 3, escaping closures need to be marked as such. And the in Swift 3, escaping closures need to be marked as such. And the atributo @ escape` nos permite hacer eso.

  • Un escaping closure @escaping es un cierre que se llama después de que la función que se pasó a devuelve. En otras palabras, sobrevive a la función a la que se le pasó. Los casos de uso comunes para esto son:

    • Llamadas asincrónicas; redes.
    • Funciones almacenadas como variables; pensar acciones y devoluciones de llamadas proporcionadas.
    • Programación de tareas en una cola de despacho.


    Un buen ejemplo de un escaping closure es un completion handler . Muchas funciones que inician una operación asincrónica toman un argumento de cierre como un controlador de finalización. La función regresa después de comenzar la operación, pero el cierre no se llama hasta que se completa la operación; el cierre debe escapar, para llamarse más tarde.

Lea más aquí: publicación mediana , publicación media , docs


import UIKit import Alamofire

// modelo

class ShortlistCountResponse : Decodable { var response : String? var data : ShortlistcountData? } class ShortlistcountData : Decodable { var totalpropFavcount : Int? var totalprojFavcount : Int? }

// Clase genérica Definición ......

static func fetchGenericData<T: Decodable>(urlString: String,params : [String:Any], completion: @escaping (T) -> ()) { let url = urlString let headers = ["Content-Type": "application/x-www-form-urlencoded", "Accept":"application/json"] Alamofire.request(url, method: .post, parameters:params, encoding: URLEncoding.default, headers: headers).responseJSON { response in print(response.request?.urlRequest ?? "") print(params) print(response.data ?? "") print(response.value ?? "") switch(response.result) { case .success(_): if let data = response.data{ do { let gotData = try JSONDecoder().decode(T.self, from: data) completion(gotData) } catch let jsonErr { print("Error serializing json:", jsonErr) ActivityIndicator.dismissActivityView() } DispatchQueue.main.async { ActivityIndicator.dismissActivityView() } } break case .failure(_): print(response.result.error ?? "") ActivityIndicator.dismissActivityView() break } } }

// llamada divertida

override func viewDidLoad() { super.viewDidLoad() let userID = "" let languageID = "" let params = ["userID":userID,"languageID":languageID] var appDelegate: AppDelegate? Service.fetchGenericData(urlString: "your url...", params: params) { (shortlistCountResponse : ShortlistCountResponse) in print(shortListCountResponse.data.totalprojFavcount ?? 0) } }