将objc_setAssociatedObject与弱引用一起使用

ult*_*ous 21 weak-references objective-c objective-c-runtime

我知道OBJC_ASSOCIATION_ASSIGN存在,但是如果目标对象被释放,它是否会将引用归零?或者它是否像旧时代那样需要获取nil-ed或者我们以后会冒错误访问?

0xc*_*ced 33

正如超级神奇所证明的那样,OBJC_ASSOCIATION_ASSIGN不会将弱引用归零,并且您有可能访问已解除分配的对象.但是你自己很容易实现.你只需要一个简单的类来包装一个弱引用的对象:

@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
Run Code Online (Sandbox Code Playgroud)

然后你必须将WeakObjectContaineras 关联为OBJC_ASSOCIATION_RETAIN(_NONATOMIC):

objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainer alloc] initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
Run Code Online (Sandbox Code Playgroud)

并使用该object属性访问它以获得归零弱引用:

id object = [objc_getAssociatedObject(self, &MyKey) object];
Run Code Online (Sandbox Code Playgroud)

  • 因为` - [NSValue nonretainedObjectValue]`不返回*weak*对象,因此不会对弱引用进行归零. (2认同)
  • 关联对象在其所有者被解除分配时自动[解除分配](https://github.com/aosm/objc4/blob/345130a19b83510b81277864a79226111b9da3ea/runtime/objc-runtime-new.mm#L6825). (2认同)

Vad*_*dim 10

还有一个选项类似于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);
}
Run Code Online (Sandbox Code Playgroud)


ult*_*ous 4

尝试过后,答案是否定的。

我在 iOS 6 模拟器下运行了以下代码,但它可能与运行时的先前迭代具有相同的行为:

NSObject *test1 = [NSObject new];

NSObject __weak *test2 = test1;

objc_setAssociatedObject(self, "test", test1, OBJC_ASSOCIATION_ASSIGN);

test1 = nil;

id test3 = objc_getAssociatedObject(self, "test");
Run Code Online (Sandbox Code Playgroud)

最后,test1和test2都是nil,test3是之前存储在test1中的指针。使用 test3 将导致尝试访问已被释放的对象。