Ricorda anche che possono verificarsi cicli di mantenimento se il tuo blocco fa riferimento a un altro oggetto che quindi mantieneself
.
Non sono sicuro che Garbage Collection possa aiutare in questi cicli di conservazione. Se l'oggetto che conserva il blocco (che chiamerò l'oggetto server) sopravvive self
(l'oggetto client), il riferimento aself
all'interno del blocco non sarà considerato ciclico fino al rilascio dell'oggetto di conservazione stesso. Se l'oggetto server sopravvive di gran lunga ai suoi client, potresti avere una significativa perdita di memoria.
Dal momento che non esistono soluzioni pulite, consiglierei le seguenti soluzioni alternative. Sentiti libero di sceglierne uno o più per risolvere il problema.
- Utilizzare i blocchi solo per il completamento e non per eventi a tempo indeterminato. Ad esempio, utilizzare i blocchi per metodi simili
doSomethingAndWhenDoneExecuteThisBlock:
e non per metodi similisetNotificationHandlerBlock:
. I blocchi utilizzati per il completamento hanno una durata definita e devono essere rilasciati dagli oggetti server dopo essere stati valutati. Questo impedisce al ciclo di mantenimento di sopravvivere troppo a lungo anche se si verifica.
- Fai quella danza di riferimento debole che hai descritto.
- Fornire un metodo per ripulire l'oggetto prima che venga rilasciato, che "disconnetta" l'oggetto dagli oggetti server che potrebbero contenere riferimenti ad esso; e chiama questo metodo prima di chiamare il rilascio sull'oggetto. Mentre questo metodo è perfetto se il tuo oggetto ha un solo client (o è un singleton in un certo contesto), ma si romperà se ha più client. Fondamentalmente stai sconfiggendo il meccanismo di conteggio del mantenimento qui; questo è simile a chiamare
dealloc
invece di release
.
Se stai scrivendo un oggetto server, prendi gli argomenti a blocchi solo per il completamento. Non accettare argomenti a blocchi per callback, come setEventHandlerBlock:
. Invece, ripiega sul modello delegato classico: crea un protocollo formale e pubblicizza un setEventDelegate:
metodo. Non conservare il delegato. Se non si desidera nemmeno creare un protocollo formale, accettare un selettore come callback delegato.
E, infine, questo schema dovrebbe suonare allarmi:
- (vuoto) dealloc {
[myServerObject releaseCallbackBlocksForObject: self];
...
}
Se stai provando a sganciare blocchi che potrebbero riferirsi self
dall'interno dealloc
, sei già nei guai. dealloc
potrebbe non essere mai chiamato a causa del ciclo di conservazione causato dai riferimenti nel blocco, il che significa che il tuo oggetto semplicemente perderà fino a quando l'oggetto server non viene deallocato.
self
delegatithis
solo per capovolgere le cose. In JavaScript chiamo le miethis
chiusureself
, quindi è bello ed equilibrato. :)