Próbuję zachować odniesienie do bloku, który został przekazany do mojej klasy za pomocą metody, aby zadzwonić w późniejszym czasie. Mam jednak problem z utrzymaniem odniesienia do niego.Blok zostaje zwolniony, podczas gdy w NSDictionary (ARC)
Oczywistym sposobem, pomyślałem, było dodanie go do kolekcji ivar, z których wszystkie mają utrzymywać silne odniesienia do ich zawartości. Ale kiedy próbuję ją wyciągnąć, jest zero.
Kod jest dość prosta:
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
}
Co się dzieje?
Aktualizacja: Próbowałem go [callback copy]
i tylko callback
włożeniem do słownika, ani prace.
Aktualizacja 2: Gdybym tylko trzymać mój blok się na NSMutableSet, tak długo, jak ja to nazywam copy
, jestem w porządku. Działa świetnie. Ale jeśli jest w NSDictionary, nie ma.
Rzeczywiście przetestowałem to poprzez umieszczenie punktu przerwania zaraz po utworzeniu NSDict i wywołanie zwrotne nigdy nie zostanie wstawione. W opisie wyraźnie widać "1 parę klucz-wartość", a nie dwie.
W tej chwili używam specjalistycznej klasy, która działa jak pojemnik. Właściwość callback
jest zadeklarowana jako strong
; Nie muszę nawet używać copy
.
Pytanie pozostaje jednak następujące: dlaczego tak się dzieje? Dlaczego NSDictionary nie będzie przechowywać bloku? Czy ma to coś wspólnego z tym, że celuję w system operacyjny iOS 4.3, a zatem ARC musi być wbudowany jako biblioteka statyczna?
Aktualizacja 3: Panie i panowie: Jestem idiotą.
Przedstawiony tutaj kod był oczywiście uproszczoną wersją rzeczywistego kodu; w szczególności, pozostawił niektóre pary klucz/wartość ze słownika.
Jeśli przechowywania wartości w NSDictionary za pomocą [NSDictionary dictionaryWithObjectsAndKeys:]
, to lepiej być cholernie pewien jedna z tych wartości nie jest nil
.
Jednym z nich był.
ICYMI, było przyczyną wcześniejszego zakończenia listy argumentów. Miałem argument typu userInfo przekazywany do jednej z metod "dodaj do kolejki" i możesz oczywiście przekazać "zero". Następnie, kiedy skonstruowałem słownik, zarzucenie tego argumentu spowodowało, że konstruktor pomyślał, że zakończyłem listę argumentów. @"callback"
była ostatnią wartością w konstruktorze słownika i nigdy nie była przechowywana.
Skopiowałem i wkleiłem ten kod za pomocą [kopii wywołania zwrotnego] i wszystko działało dobrze. –
Funkcja functionToBeCalledLater występuje w innej iteracji pętli uruchamiania, chociaż nie sądziłem, że ma to znaczenie, ale może ma to coś wspólnego z tym, gdzie ARC umieszcza swoje zachowania i wydania. –
Nazwałem functionToBeCalledLater na innej iteracji runloopa również (zrobiłem dla niego mały przycisk i trafiłem to kilka razy). –