Sto cercando di mantenere un riferimento a un blocco che è stato passato alla mia classe con un metodo, per chiamare in un secondo momento. Sto avendo problemi, tuttavia, mantenendo un riferimento ad esso.Il blocco viene rilasciato mentre in NSDictionary (ARC)
Il modo ovvio, ho pensato, era di aggiungerlo a una raccolta di ivar, che dovrebbero mantenere forti riferimenti al loro contenuto. Ma quando provo a tirarlo indietro, è zero.
Il codice è piuttosto semplice:
typedef void (^DataControllerCallback)(id rslt);
@interface DataController : NSObject {
NSMutableArray* queue;
}
- (void) addBlock:(DataControllerCallback)callback;
- (void) functionToBeCalledLater;
@end
@implementation DataController
- (id) init {
self = [super init];
if (self != nil) {
queue = [NSMutableArray new];
}
return self;
}
- (void) addBlock:(DataControllerCallback)callback {
NSDictionary* toAdd = [NSDictionary dictionaryWithObjectsAndKeys:
[callback copy], @"callback",
@"some other data", @"data", nil];
[queue addObject:toAdd];
}
- (void) functionToBeCalledLater {
NSDictionary* dict = [queue lastObject];
NSLog(@"%@", [dict objectForKey:@"data"]; //works
DataControllerCallback callback = [dict objectForKey:@"callback"]; //this is nil
callback(@"an arguemnt"); //EXC_BAD_ACCESS
}
Cosa sta succedendo?
Aggiornamento: Ho provato con [callback copy]
e proprio callback
inserendo nel dizionario, né opere.
Update 2: Se ho appena bastone il mio blocco in un NSMutableSet, a patto che io chiamo copy
, sto bene. Funziona alla grande. Ma se è in un NSDictionary, non è così.
L'ho effettivamente testato mettendo un breakpoint subito dopo che NSDict è stato creato e il callback non viene mai inserito. La descrizione riporta chiaramente "1 coppia chiave-valore", non due.
Attualmente mi sto aggirando con una classe specializzata che funge solo da contenitore. La proprietà callback
viene dichiarata come strong
; Non ho nemmeno bisogno di usare copy
.
La domanda continua, tuttavia: perché sta succedendo? Perché un archivio NSDictionary non è un blocco? Ha qualcosa a che fare con il fatto che sto prendendo di mira iOS 4.3 e quindi ARC deve essere incorporato come libreria statica?
Aggiornamento 3: Signore e signori: sono un idiota.
Il codice che ho presentato qui era ovviamente una versione semplificata del codice attuale; in particolare, stava lasciando alcune coppie chiave/valore fuori dal dizionario.
Se sei memorizzare un valorein un NSDictionary utilizzando [NSDictionary dictionaryWithObjectsAndKeys:]
, è meglio essere dannatamente sicuro uno di questi valori non è nil
.
Uno di questi era.
ICYMI, causava una chiusura anticipata dell'elenco argomenti. Avevo un argomento user-type passato in uno dei metodi "aggiungi alla coda" e potevi, ovviamente, passare "nil". Poi, quando ho costruito il dizionario, il chucking in quell'argomento ha indotto il costruttore a pensare che avevo terminato la lista degli argomenti. @"callback"
era l'ultimo valore nel costruttore dizionario e non veniva mai memorizzato.
Ho copiato e incollato questo codice con [callback copy] e tutto ha funzionato correttamente. –
Il 'functionToBeCalledLater' si verifica in una diversa iterazione del ciclo di esecuzione, anche se non pensavo che fosse importante, ma forse ha qualcosa a che fare con la posizione di conservazione e rilascio di ARC. –
Ho chiamato functionToBeCalledLater su una diversa iterazione del runloop anche (fatto un piccolo pulsante per questo, e lo ho colpito più volte in effetti) –