Używanie objc setassocjatedobject ze słabymi referencjami
Wiem, że OBJC_ASSOCIATION_ASSIGN istnieje, ale czy zeruje odniesienie, jeśli obiekt docelowy jest dealloced? A może to jak za dawnych czasów, kiedy Referencja musi być zerowa, albo ryzykujemy zły dostęp później?
4 answers
Jak wykazał ultramiraculous, OBJC_ASSOCIATION_ASSIGN
nie zeruje słabego odniesienia i ryzykujesz dostęp do dealokowanego obiektu. Ale jest to dość łatwe do wdrożenia siebie. Po prostu potrzebujesz prostej klasy, aby owinąć obiekt ze słabym odniesieniem:
@interface WeakObjectContainer : NSObject
@property (nonatomic, readonly, weak) id object;
@end
@implementation WeakObjectContainer
- (instancetype) initWithObject:(id)object
{
if (!(self = [super init]))
return nil;
_object = object;
return self;
}
@end
Następnie należy skojarzyć WeakObjectContainer
jako OBJC_ASSOCIATION_RETAIN (_NONATOMIC):
objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainer alloc] initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
I użyj właściwości object
, aby uzyskać dostęp do niej w celu uzyskania zerującego słabego odniesienia:
id object = [objc_getAssociatedObject(self, &MyKey) object];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-30 15:09:19
Jeszcze jedna opcja podobna do WeakObjectContainer
:
- (id)weakObject {
id (^block)() = objc_getAssociatedObject(self, @selector(weakObject));
return (block ? block() : nil);
}
- (void)setWeakObject:(id)object {
id __weak weakObject = object;
id (^block)() = ^{ return weakObject; };
objc_setAssociatedObject(self, @selector(weakObject),
block, OBJC_ASSOCIATION_COPY);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-23 18:21:21
Po wypróbowaniu, odpowiedź brzmi nie.
Uruchomiłem poniższy kod pod symulatorem iOS 6, ale prawdopodobnie zachowałby się tak samo z poprzednimi iteracjami runtime:
NSObject *test1 = [NSObject new];
NSObject __weak *test2 = test1;
objc_setAssociatedObject(self, "test", test1, OBJC_ASSOCIATION_ASSIGN);
test1 = nil;
id test3 = objc_getAssociatedObject(self, "test");
W końcu, test1 i test2 są zerowe, a test3 jest wskaźnikiem wcześniej zapisanym w test1. Użycie test3 skutkowałoby próbą uzyskania dostępu do obiektu, który został już dealloced.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-03 00:42:29
To zachowanie nie jest określone w dokumentach ani nagłówkach, więc prawdopodobnie jest to szczegół implementacji, na który nie powinieneś liczyć, nawet jeśli byłeś w stanie rozpoznać, jakie jest obecne zachowanie. Domyślam się, że jest to a nie zerowane. Oto dlaczego:
Ogólnie rzecz biorąc, nie ma potrzeby nil
out referencji w iVars podczas -dealloc
. Jeśli obiekt jest deallocowany, nie powinno mieć znaczenia, czy jego Ivary zostały wyzerowane, ponieważ jakikolwiek dalszy dostęp do deallocowanego obiektu lub jego iVars jest sam w sobie błędem programistycznym. W rzeczywistości słyszałem, że niektórzy twierdzą, że lepiej Nie usuwać odniesienia podczas -dealloc
, ponieważ to sprawi, że błędne dostępy będą bardziej oczywiste/ujawniają błędy wcześniej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-15 19:28:37