Desmistificando @escapar, @não escapar, @autoclosure e curry função
os Fechamentos são auto-contidos blocos de funcionalidade que pode ser passado em volta e utilizados em seu código.
— Apple
Closures can capture and store references to any constants and variables from the context in which they are defined, known as closing over hence Closure. Você pode pensar em um fechamento como sendo uma função que não tem um nome próprio e captura quaisquer valores de seu ambiente. Funções e fechamentos são objetos de primeira classe no Swift: você pode armazená-los, passá-los como argumentos para funções, e tratá-los como você faria qualquer outro valor ou objeto. Passar fechamentos como tratadores de acabamento é um padrão comum em muitas APIs. A Standard Swift library usa fechamentos principalmente para movimentação de eventos e callbacks.
funções são blocos de código auto-suficientes que executam uma tarefa específica. Você dá a uma função um nome que identifica o que ela faz, e este nome é usado para “chamar” a função para executar sua tarefa quando necessário. Você define uma função com a palavra-chave func
. Funções não podem levar nenhum a muitos parâmetros, parâmetros variádicos e retornar nenhum ou vários parâmetros.
Tipos de Função
tipo de Função é feita de tipos de parâmetros e o tipo de retorno da função. Por exemplo, o tipo de função é:(Int, Int) -> Int
isto pode ser lido como: “uma função que tem dois parâmetros, ambos do tipo Int
e que retorna um valor do tipo Int
.”Tipo de função pode ser definido como parâmetro ou tipo de retorno de função.
tipos de funções podem ser atribuídos a qualquer variável como esta:
var mathFunction: (Int, Int) -> Int = add
funções são casos especiais de encerramento. Os encerramentos assumem uma de três formas::
- funções globais: eles têm um nome e não podem capturar valor.
- funções aninhadas: elas têm um nome e podem capturar valores de sua função envolvente.
- expressões de encerramento: eles não têm nome e podem capturar valores de seu contexto circundante.Expressão De Encerramento:
Fechamento pode ser criado, colocando um tipo de função dentro de chavetas e
in
palavra-chave, depois de o tipo de retorno.os argumentos Estenográficos podem se referir a uma posição.
,
,
,
e assim por diante.
Implícito Retorna de Encerramento:
Único-expressão fechamentos implicitamente pode retornar o resultado de sua única expressão, omitindo a
return
palavra-chave de sua declaração.Para uma de várias linhas de expressão encerramento,
return
palavra-chave não pode ser omitido.Encerramento Posterior:
se você precisar passar uma expressão de fechamento para uma função como o último argumento da função e a expressão de fechamento é muito longa, ela pode ser escrita como fechamento posterior. Um fechamento posterior é escrito após os parênteses da chamada de função (), mesmo que ainda seja um argumento para a função. Quando você usa a sintaxe de encerramento posterior, você não escreve o rótulo de argumento para o encerramento como parte da chamada de função.
Se o fechamento é o último parâmetro de um método, em seguida, swift permite escrever assim 🖕
A utilização de final de fechamento de sintaxe ordenadamente encapsula o encerramento da funcionalidade imediatamente após a função que o fechamento de suporte, sem a necessidade de moldar todo o fechamento dentro de
reduce(_:)
método do exterior parênteses.valores de captura:
um fecho pode capturar constantes e variáveis do contexto circundante no qual é definido. O fechamento pode então se referir e modificar os valores dessas constantes e variáveis de dentro de seu corpo, mesmo que o escopo original que definiu as constantes e variáveis não exista mais.
in Swift, the simplest form of a closure that can capture values is a nested function, written within the body of another function. Uma função aninhada pode capturar qualquer dos argumentos de sua função externa e também pode capturar quaisquer constantes e variáveis definidas dentro da função externa.
esta função
makeIncrementer
aceita um argumento, ou seja, Int como input e devolve um tipo de função, ou seja() -> Int
. Isto significa que retorna uma função, ao invés de um valor simples. A função que retorna não tem parâmetros, e retorna um valorInt
cada vez que é chamado.aqui
amount
é argumento,runningTotal
é declarado como variável e inicializado com 0. Função aninhadaincrementer
capturaamount
erunningTotal
do contexto circundante.vejamos
makeIncrementer
em acção:Nota: Como uma otimização, Swift pode capturar e armazenar uma cópia de um valor se esse valor não for modificado por um fechamento, e se o valor não for modificado após o fechamento ser criado.
Swift também lida com toda a gestão de memória envolvida na eliminação de variáveis quando elas já não são necessárias.
para se livrar da expressão de fechamento longo no argumento de função você pode usar typealias.
os parâmetros de encerramento estavam escapando por padrão antes do Swift 3. Um fechamento não escaparia do corpo da função se os parâmetros de fechamento são marcados como não escapando
no Swift 3 foi revertido. Quando você está passando um fechamento como o argumento da função, o fechamento é executado com o corpo da função e retorna o compilador de volta. À medida que a execução termina, o fechamento passado sai do escopo e não tem mais existência na memória.
o mínimo que precisa de saber é que os parâmetros de Fecho não estão a escapar por omissão, se quiser escapar à execução de Fecho, terá de usar o @escaping com os parâmetros de Fecho.
Lifecycle of the non-escaping closure:
1. Passar o fechamento como um argumento de função, durante a chamada de função.
2. Faça algum trabalho em função e depois execute o encerramento.
3. A função retorna.devido a uma melhor gestão de memória e otimizações, a Swift mudou todos os encerramentos para não escapar por padrão.
CaptureList.swift
é um exemplo de fechamento não-escapatória.Nota: @anotação sem Escape aplica-se apenas aos tipos de funções
dispositivos de escape:
um fecho é dito para escapar de uma função quando o fecho é passado como um argumento para a função, mas é chamado após a função retorna. Marcar um fecho com
@escaping
significa que você tem que se referir aself
explicitamente dentro do fecho.ciclo de vida do fecho @escaping:
1. Passar o fechamento como argumento de função, durante a chamada de função.
2. Faça algum trabalho adicional na função.
3. Função executar o fecho assíncronamente ou armazenado.
4. A função retorna.vamos ver onde os encerramentos estão por omissão a escapar:
- Variáveis de tipo de função estão implícitos escapar
- typealiases estão implícitos escapar
- Opcional vedantes estão implícitos escapar
Erro Comum:
a Atribuição de não sair de encerramento para escapar de encerramento. Existem 2 maneiras de corrigir isso:
- Marca encerramento escapar
- Ou mantenha o padrão @noescape comportamento, fazendo o fechamento opcional
Autoclosures:
Swift
@autoclosure
atributo permite que você defina um argumento que automaticamente fica envolto em um fechamento. Não é preciso argumentos, e quando é chamado, ele retorna o valor da expressão que está embrulhada dentro dele. Esta conveniência sintática permite que você omita Chavetas em torno do parâmetro de uma função, escrevendo uma expressão normal em vez de um fechamento explícito.por exemplo, a função
assert(condition:message:file:line:)
toma um autoclosure para os seus parâmetroscondition
emessage
; o seu parâmetrocondition
é avaliado apenas em compilações de depuração e o seu parâmetromessage
é avaliado apenas secondition
forfalse
.func assert(_ expression: @autoclosure () -> Bool,
_ message: @autoclosure () -> String) {}to use
@autoclosure
with@escaping
attribute syntax is:@autoclosure @escaping () -> Bool
fechos vs blocos:
” Swift clasures and Objective-C blocks are compatible so you can pass Swift clasures to Objective-C methods that expect blocks. Fechamentos Swift e funções têm o mesmo tipo para que você possa até passar o nome de uma função Swift. Os encerramentos têm semântica de captura semelhante aos blocos, mas diferem de uma maneira chave: as variáveis são mutáveis ao invés de copiadas. Em outras palavras, o comportamento de __bloco no Objective-C é o comportamento padrão para variáveis no Swift.”
Encerramentos vs delegados:
a solução depende do problema. Além disso, a Apple está mudando seu foco para Padrão de Callback.
UIAlertAction
é um exemplo disso.https://medium.com/@abhimuralidharan/functional-swift-all-about-closures-310bc8af31dd
https://medium.com/@kumarpramod017/what-do-mean-escaping-and-nonescaping-closures-in-swift-d404d721f39d
https://oleb.net/blog/2016/10/optional-non-escaping-closures/
https://swiftunboxed.com/lang/closures-escaping-noescape-swift3/
https://medium.com/@johnsundell/using-autoclosure-when-designing-swift-apis-67fe20a8b2e