我知道OBJC_ASSOCIATION_ASSIGN存在,但如果目标对象被解除分配,它会将引用归零吗?或者它是否像旧时代的参考需要被取消或者我们以后会冒错误的访问?
答案 0 :(得分:32)
正如超级神奇所证明的那样,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
然后您必须将WeakObjectContainer
关联为OBJC_ASSOCIATION_RETAIN(_NONATOMIC):
objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainer alloc] initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
并使用object
属性访问它以获得归零弱引用:
id object = [objc_getAssociatedObject(self, &MyKey) object];
答案 1 :(得分:5)
另一个类似于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);
}
答案 2 :(得分:3)
尝试后,答案是否定的。
我在iOS 6 Simulator下运行了以下代码,但它可能与之前的运行时迭代具有相同的行为:
NSObject *test1 = [NSObject new];
NSObject __weak *test2 = test1;
objc_setAssociatedObject(self, "test", test1, OBJC_ASSOCIATION_ASSIGN);
test1 = nil;
id test3 = objc_getAssociatedObject(self, "test");
最后,test1和test2为nil,test3是先前存储在test1中的指针。使用test3会导致尝试访问已经解除分配的对象。
答案 3 :(得分:0)
我可以告诉您在文档或标题中未指定此行为,因此即使您能够辨别当前行为是什么,它也可能是您不应指望的实现细节。我猜它是不归零。原因如下:
通常,在nil
期间,无需{i} {i}} iVars中的引用。如果一个对象被解除分配,那么它的iVars是否被清零也无关紧要,因为对dealloced对象或其iVars的任何进一步访问本身就是一个编程错误。事实上,我听到有人认为在-dealloc
期间不清除引用更好,因为它会使错误的访问更多明显/更快地暴露错误
答案 4 :(得分:0)
通过0xced(具有类型支持)的答案的快速版本:
public class WeakObjectContainer<T: AnyObject>: NSObject {
private weak var _object: T?
public var object: T? {
return _object
}
public init(with object: T?) {
_object = object
}
}