C'è un modo per specificare che un particolare argomento del metodo ha semantica debole?
Questo non è ciò che sta facendo l'esempio del codice Objective-C. Hai una semantica accidentalmente quasi debole e hai un comportamento indefinito (condizioni di competizione) che i veri riferimenti deboli non hanno.
myMethod
può inviare un messaggio in la-la-terra in qualsiasi punto di sequenza (il primo NSLog
dichiarazione o la seconda, o anche nel mezzo della NSLog
da qualche parte ... anche se ARC non Elide la conservano di arg0
voi stai ancora correndo la versione principale della coda o peggio, mantenendo un oggetto zombi).
Dichiarazione qualcosa come __block
significa semplicemente allocare una fessura nell'ambiente mucchio per il blocco (perché dispatch_async
è garantito per lasciare che il blocco sfuggire promuoverà da un blocco stack allocato ad un blocco mucchio, e uno degli slot di archiviazione in quell'ambiente heap block sarà per la variabile __block
. In ARC il blocco avrà automaticamente Block_copy
chiamato, forse più appropriato denominato Block_copy_to_heap
).
Ciò significa che entrambe le istanze di esecuzione del blocco punteranno a questa stessa posizione di memoria.
Se aiuta, immagina questo codice davvero stupido che ha una condizione di gara evidente. Ci sono 1000 blocchi in coda contemporaneamente che tentano tutti di modificare unsafe
. Siamo quasi sicuri di eseguire le dichiarazioni sgradevoli all'interno del blocco if perché il nostro compito e il confronto non sono atomici e stiamo combattendo per la stessa posizione di memoria.
static volatile size_t unsafe = 0;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(1000, queue, ^(size_t instance) {
unsafe = instance;
if (unsafe != instance) {
FORMAT_ALL_STORAGE();
SEND_RESIGNATION_EMAIL();
WATCH_THE_WORLD_BURN();
}
});
Il tuo esempio Swift non ha lo stesso problema perché il blocco che non modifica il valore probabilmente cattura (e mantiene) l'oggetto in modo non vede la modifica dal l'altro blocco.
Spetta al creatore di una chiusura gestire le conseguenze della gestione della memoria in modo da non poter creare un contratto API che non imponga cicli di conservazione in una chiusura, oltre a contrassegnare qualcosa come @noescape
nel qual caso Swift ha vinto " t fare qualsiasi ritenzione/rilascio o altra gestione della memoria perché il blocco non sopravvive al frame dello stack corrente. Ciò preclude la spedizione asincrona per ovvi motivi.
Se si desidera presentare un contratto API che risolva ciò, è possibile che un tipo adotti un protocollo protocol Consumer: class { func consume(thing: Type) }
quindi all'interno dell'API mantieni un riferimento debole alle istanze Consumer
.
Un'altra tecnica è di accettare una versione al curry di una funzione di esempio e debolmente catturare self
:
protocol Protocol: class { }
typealias FuncType =() -> Void
var _responders = [FuncType]()
func registerResponder<P: Protocol>(responder: P, usingHandler handler: (P) ->() -> Void) {
_responders.append({ [weak responder] in
guard let responder = responder else { return }
handler(responder)()
})
}
class Inst: Protocol {
func myFunc() {
}
}
let inst = Inst()
registerResponder(inst, usingHandler: Inst.myFunc)
Non è possibile al momento, è possibile farlo prima di Swift 2.0 con '[weak yourObject]' all'inizio della chiusura. Vedi anche [here] (http://stackoverflow.com/questions/24717460/cant-make-weak-reference-to-closure-in-swift) dove mostrano alcune soluzioni alternative – Kametrixom
Capisco che la chiusura debole potrebbe essere una soluzione ma non risolve il problema, non voglio che tutti i consumatori dell'API siano a conoscenza dei miei dettagli di implementazione. È possibile in Swift 2? –
In che modo i consumatori possono essere consapevoli dell'implementazione dell'API in questo modo? – Kametrixom