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?

Author: ultramiraculous, 2013-05-15

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];
 28
Author: 0xced,
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);
}
 4
Author: Stream,
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.

 1
Author: ultramiraculous,
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.

EDIT: chyba źle odczytałem twoje pytanie. Chcesz "zerować słabe odniesienia". Wydaje się, że powiązana pamięć masowa nie obsługuje tych funkcji. Można zrobić trywialną klasę przelotową z jednym ivar / właściwością oznaczoną jako _ _ słaba i osiągnąć ten sam efekt, że sposób. Trochę kludgey, ale to zadziała.
 0
Author: ipmcc,
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