Почему слабое свойство связанного объекта не обнуляется, если я вызываю его геттер? - PullRequest
0 голосов
/ 14 января 2020

Хотя в 2020 году довольно глупо, что я все еще задаю вопрос об Obj C, пожалуйста, будьте терпеливы и внимательны ...

Я читаю исходный код BloksKit и столкнулся с странная ситуация.

#import <objc/runtime.h>

@interface _WeakAssociatedObjectWrapper : NSObject
@property (nonatomic, weak) id object;
@end

@implementation _WeakAssociatedObjectWrapper
@end

@interface NSObject (AddWeak)
@end

@implementation NSObject (AddWeak)
- (void)setWeakProp:(id)weakProp {
    _WeakAssociatedObjectWrapper *wrapper  = objc_getAssociatedObject(self, @selector(weakProp));
    if (!wrapper) {
        wrapper = [[_WeakAssociatedObjectWrapper alloc] init];
        objc_setAssociatedObject(self, @selector(weakProp), wrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    wrapper.object = weakProp;
}
- (id)weakProp {
    id value = objc_getAssociatedObject(self, _cmd);
    if ([value isKindOfClass:_WeakAssociatedObjectWrapper.class]) {
        return [(_WeakAssociatedObjectWrapper *)value object];
    }
    return value;
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
        {
            NSObject *prop = [[NSObject alloc] init];
            [obj setWeakProp:prop];

            [obj weakProp]; // *Weird!!
        }
        NSLog(@"Now obj.weakProp = %@", [obj weakProp]);
    }
    return 0;
}

Этот код добавляет слабый связанный объект для категории. (BlocksKit делает это)

Обратите внимание на строку *Weird!!. Если эта строка закомментирована, то она печатает (null), что разумно, поскольку prop освобождается за пределами области действия {}. С другой стороны, если он не закомментирован, он печатает <NSObject: 0xxxxx>, что указывает на то, что prop каким-то образом удерживается кем-то (или по любой другой причине?). Что здесь происходит??! (BlocksKit ведет себя так же!)

Среда: XCode 10.3

1 Ответ

0 голосов
/ 16 января 2020

Это особенность. Для случая (и любого подобного)

[obj weakProp];

в соответствии с соглашением об именах свойств / средств доступа AR C возвращает автоматически выпущенный экземпляр так что в вашем случае @autoreleasepool держит его, и тестирование, как показано ниже, может показать это.

int main(int argc, const char * argv[]) {
    NSObject *obj = [[NSObject alloc] init];
    @autoreleasepool {
        {
            NSObject *prop = [[NSObject alloc] init];
            [obj setWeakProp:prop];

            [obj weakProp]; // *Weird!!
        }
        NSLog(@"Now obj.weakProp = %@", [obj weakProp]);
    }
    NSLog(@"After autoreleased >> obj.weakProp = %@", [obj weakProp]);
    return 0;
}
...