Mi chiedo perché il tag noescape
non viene rilevato automaticamente e deve essere esplicitamente applicato.
Infatti, è in qualche modo rilevato in fase di compilazione, perché provare ad aggiungere il tag @noescape a una funzione con chiusure di escape comporta un errore.
Quindi la domanda è perché ... perché? noescape
deve essere aggiunto esplicitamente e Apple non l'ha creato per essere aggiunto automaticamente quando è necessario?
risposte:
2 per risposta № 1Modificare: Swift 3 apporta alcune modifiche qui:
- Le chiusure che non sfuggono sono quelle predefinite. Ora non devi fare domanda
@noescape
alle dichiarazioni delle funzioni che prendono le chiusure come parametri se si desidera richiedere chiusure che non sfuggano. (Invece, devi applicare@escaping
nei casi in cui tu fare pianifica di memorizzare una chiusura dopo il ritorno della tua funzione.) - La "fuga" di una chiusura ora fa parte della dichiarazione del tipo di funzione. Quindi, invece di un parametro che sembra
@escaping completionHandler: (Bool, Error) -> Void
, suocompletionHandler: @escaping (Bool, Error) -> Void
.
È abbastanza difficile riscrivere la mia intera risposta per riflettere questo, quindi lo lascio qui per ora ... continua a leggere per whys dietro la fuga, basta ricordare di invertire le dichiarazioni di fuga / fuga. :) O leggere Chiusure di fuga nella versione Swift 3 di The Swift Programming Language.
@noescape
non è solo un suggerimento per le ottimizzazioni del compilatore, ma fa parte dell'interfaccia che una dichiarazione di funzione presenta ai chiamanti. Se viene dichiarato un parametro per una funzione @noescape
o consente di chiudere le chiusure cambia il modo in cui un chiamante di quella funzione scrive la chiusura che passano come parametro.
Ad esempio, data la funzione (da SequenceType
):
func filter(@noescape includeElement: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.Generator.Element]
Se volessi filtrare una raccolta in base a determinati criteri che richiedono la chiamata di un metodo self
, So di poterlo fare tranquillamente senza preoccuparmi se la chiusura verrà catturata self
e creare un ciclo di conservazione.
// horribly contrived example
class Foo {
var things: [Thing]
func isCurrentlyAwesomeThing(thing: Thing) -> Bool { /*...*/ }
func thingsThatAreAwesomeRightNow() -> [Thing] {
return things.filter {
return isCurrentlyAwesomeThing($0)
}
}
}
Se filter
permesso una chiusura di fuga, la chiusura che chiama isCurrentlyAwesomeThing()
catturerebbe self
. (E quindi richiede che quel metodo sia chiamato con un esplicito self.
prefisso.) E se l'implementazione di filter
effettivamente salvato la chiusura oltre il tempo di esecuzione di quella funzione, non ci sarebbe una perdita di memoria perché la chiusura mantiene self
e self
conserva l'array di cui filter
la funzione ha ricevuto la chiusura.
Quando si chiama una funzione i cui parametri di chiusura non vengono dichiarati @noescape
, devi rendere conto di questa possibilità. Questo è il motivo per cui vedi le chiamate che aggiungono a [weak self]
lista di cattura e una forte redeclaration all'interno della chiusura per essere sicuri self
non viene deallocato durante la chiusura (o almeno un [unowned self]
nei casi in cui si è ragionevolmente certi che la chiusura non duri più a lungo di self
.)
Se i parametri di chiusura non fossero decorati come @noescape
(o come non fugare attraverso l'assenza di quel decoratore), non si dovrebbe sapere quando si chiama una funzione che richiede una chiusura, se si deve fare attenzione a ciò che cattura questa chiusura.
0 per risposta № 2
Se utilizzi un qualsiasi parametro di funzione come notescape che non puoi memorizzare in un'altra chiusura, non puoi usare dispatch_asynch e non puoi chiamare la chiusura non-noescape dalla chiusura di noescape
Lo scopo dell'attributo noescape con cui dovrebbe essere in quella chiusura