简体   繁体   English

在弱引用中使用 objc_setAssociatedObject

[英]Using objc_setAssociatedObject with weak references

I know that OBJC_ASSOCIATION_ASSIGN exists, but does it zero the reference if the target object is dealloced?我知道 OBJC_ASSOCIATION_ASSIGN 存在,但是如果目标对象被释放,它是否会将引用归零? Or is it like the old days where that reference needs to get nil-ed or we risk a bad access later on?还是像过去那样引用需要被清零,或者我们以后可能会冒着错误访问的风险?

As ultramiraculous demonstrated, OBJC_ASSOCIATION_ASSIGN does not do zeroing weak reference and you risk to access a deallocated object.正如超奇迹所证明的那样, OBJC_ASSOCIATION_ASSIGN不会将弱引用归零,并且您可能会冒着访问已释放对象的风险。 But it's quite easy to implement yourself.但是自己实现很容易。 You just need a simple class to wrap an object with a weak reference:你只需要一个简单的类来用弱引用包装一个对象:

@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

Then you must associate the WeakObjectContainer as OBJC_ASSOCIATION_RETAIN(_NONATOMIC):然后您必须将WeakObjectContainer关联为 OBJC_ASSOCIATION_RETAIN(_NONATOMIC):

objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainer alloc] initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC);

and use the object property to access it in order to get a zeroing weak reference:并使用object属性访问它以获得归零弱引用:

id object = [objc_getAssociatedObject(self, &MyKey) object];

One more option similar to WeakObjectContainer : WeakObjectContainer一种类似于WeakObjectContainer选项:

- (id)weakObject {
    id (^block)(void) = objc_getAssociatedObject(self, @selector(weakObject));
    return (block ? block() : nil);
}

- (void)setWeakObject:(id)object {
    id __weak weakObject = object;
    id (^block)(void) = ^{ return weakObject; };
    objc_setAssociatedObject(self, @selector(weakObject),
                             block, OBJC_ASSOCIATION_COPY);
}

After trying it out, the answer is NO.尝试之后,答案是否定的。

I ran the following code under the iOS 6 Simulator, but it would probably have the same behavior with previous iterations of the runtime:我在 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");

In the end, test1 and test2 are nil, and test3 is the pointer previously stored into test1.最后,test1和test2都是nil,test3就是之前存入test1的指针。 Using test3 would result in trying to access an object that had already been dealloced.使用 test3 会导致尝试访问已经被释放的对象。

Swift version of answer by 0xced (with type support): 0xced 的 Swift 版本答案(带类型支持):

public class WeakObjectContainer<T: AnyObject>: NSObject {

    private weak var _object: T?

    public var object: T? {
        return _object
    }

    public init(with object: T?) {
        _object = object
    }

}

This behavior isn't specified in the docs or headers as best I can tell, so it's likely an implementation detail that you shouldn't count on, even if you were able to discern what the current behavior is.尽我所知,此行为并未在文档或标题中指定,因此它可能是您不应该依赖的实现细节,即使您能够辨别当前行为是什么。 I would guess that it is not zeroed out.我猜它没有被清零。 Here's why:原因如下:

In general, there is no need to nil out references in iVars during -dealloc .在一般情况下,没有必要到nil期间出实例变量的引用-dealloc If an object is dealloced, it shouldn't matter if its iVars were zeroed out, because any further accessing of the dealloced object or its iVars is, in and of itself, a programming error.如果一个对象被释放,它的 iVar 是否被清零应该无关紧要,因为对释放的对象或其 iVar 的任何进一步访问本身就是一个编程错误。 In fact, I've heard some argue that it's better to not clear out references during -dealloc , because it will make erroneous accesses more obvious/expose bugs sooner.事实上,我听过一些争论,在-dealloc期间最好不要清除引用,因为它会使错误访问明显/更快地暴露错误。

EDIT: Oh, I guess I misread your question.编辑:哦,我想我误读了你的问题。 You want "zeroing weak references".你想要“归零弱引用”。 Associated storage doesn't appear to support those.关联存储似乎不支持这些。 You could make a trivial pass-through class with one ivar/property marked as __weak and achieve the same effect that way.您可以使用一个标记为 __weak 的 ivar/property 制作一个简单的传递类,并以这种方式实现相同的效果。 A little kludgey, but it'd work.有点笨拙,但它会起作用。

In case people still need a workaround for this, here is a solution in Swift to replace the normal objc_getAssociatedObject with a custom one to handle weak objects:如果人们仍然需要解决这个问题,这里有一个 Swift 中的解决方案,用自定义的objc_getAssociatedObject替换普通的objc_getAssociatedObject来处理弱对象:

func objc_getAssociatedWeakObject(_ object: AnyObject, _ key: UnsafeRawPointer) -> AnyObject? {
    let block: (() -> AnyObject?)? = objc_getAssociatedObject(object, key) as? (() -> AnyObject?)
    return block != nil ? block?() : nil
}

func objc_setAssociatedWeakObject(_ object: AnyObject, _ key: UnsafeRawPointer, _ value: AnyObject?) {
    weak var weakValue = value
    let block: (() -> AnyObject?)? = {
        return weakValue
    }
    objc_setAssociatedObject(object, key, block, .OBJC_ASSOCIATION_COPY)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 objc_setAssociatedObject在iOS中不可用吗? - Is objc_setAssociatedObject not available in iOS? 理解 objc_setAssociatedObject 中的 UnsafeRawPointer - Understanding UnsafeRawPointer in objc_setAssociatedObject 在Swift中使用objc_setAssociatedObject时提前调用dealloc / deinit - dealloc/deinit called early when using objc_setAssociatedObject in swift 使用objc_setAssociatedObject为UITableViewCell传递UIButton @selector参数 - using objc_setAssociatedObject to pass UIButton @selector argument for UITableViewCell 所有子类的类别集中的objc_setAssociatedObject - objc_setAssociatedObject in a category sets for all subclasses objc_setAssociatedObject在iPhone模拟器中不可用 - objc_setAssociatedObject unavailable in iPhone simulator objc_setAssociatedObject保留原子或非原子 - objc_setAssociatedObject retain atomic or nonatomic 删除nil的objc_setAssociatedObject - 是否已进行策略检查? - objc_setAssociatedObject with nil to remove - is policy checked? 对类对象使用objc_setAssociatedObject是否正确? - Is it correct to use objc_setAssociatedObject for class object? 使用objc_setAssociatedObject将ivars添加到类别 - Adding ivars to a Category with objc_setAssociatedObject
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM