iOS如何在容器类(如NSMutableSet)中使用弱引用(weak reference)

http://blog.sina.com.cn/s/blog_48d4cf2d0102v1jh.html

在项目中有某个功能需要用到多个delegate对象,这就需要把delegate放到容器中,但又不想保存强引用导致delegate对象不能被释放。所以希望能在容器中只保存delegate对象的弱引用。搜索发现大家常用的方法应该是采用NSValue 的valueWithNonretainedObject 和  nonretainedObject 来对弱引用进行封装。但是我测试发现,这么做虽然不会阻止对象的释放,但是对象释放后nonretainedObject 返回的并不是nil。这就很要命了。因为一个合适的弱引用应该有两个语义:

      1、不会阻止对象释放 (这点做到了)
      2、对象释放后置空 (这点并不满足)
      搜索: http://stackoverflow.com/questions/9336288/nsarray-of-weak-references-to-objects-under-arc。 大家可以看里面的回答。也可以直接看我的结论:如果想要在容器中保存弱引用,有两种方法:
      1、使用支持弱引用的容器类,如:
[NSHashTable weakObjectsHashTable]
[NSPointerArray weakObjectsPointerArray]
[NSPointerArray pointerArrayWithOptions:]
      2、自己实现一个弱引用的封装。
      由于我只是想要一个set,没找到支持弱引用的set容器。所以我就使用第二个方法定义了WeakReferenceWrapper 来对弱引用进行封装。上代码:
==============================================
 @interface WeakReferenceWrapper : NSObject

+(id) wrapNonretainedObject:(id)obj;
-(id) init;
-(id) initWithNonretainedObject:(id)obj;
-(id) get;

-(BOOL) isEqual:(id)object;
-(NSUInteger)hash;

@end

@implementation WeakReferenceWrapper {
    __weak id weakReference;
}

+(id) wrapNonretainedObject:(id)obj {
    return [[WeakReferenceWrapper alloc] initWithNonretainedObject:obj];
}

-(id) init {
    return [self initWithNonretainedObject:nil];
}

-(id) initWithNonretainedObject:(id)obj {
    self = [super init];
    if (self) {
        weakReference = obj;
    }
    return self;
}

-(id) get {
    return weakReference;
}

-(BOOL) isEqual:(id)object {
    if (!object) {
        return NO;
    }
    if (![object isKindOfClass:[self class]]) {
        return NO;
    }
    WeakReferenceWrapper* other = (WeakReferenceWrapper*) object;
    return ([self get] == [other get]);
}

-(NSUInteger)hash {
    if (weakReference) {
        return [weakReference hash];
    }
    return 0;
}
@end
==============================================
测试代码如下:
 @interface Foo: NSObject
-(id) init;
-(void) dealloc;
@end

@implementation Foo
-(id) init {
    self = [super init];
    NSLog(@"init");
    return self;
}
-(void) dealloc {
    NSLog(@"dealloc");
}
@end

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        NSMutableSet* foos = [[NSMutableSet alloc] init];
        Foo* foo1 = [[Foo alloc] init];
        WeakReferenceWrapper* weakFoo1 = [WeakReferenceWrapper wrapNonretainedObject:foo1];
        NSLog(@"%d", [foos containsObject:weakFoo1]);
        [foos addObject:weakFoo1];
        NSLog(@"%d", [foos containsObject:weakFoo1]);
        for (WeakReferenceWrapper* value in foos) {
            NSLog(@"%p", [value get]);
        }
        {
            Foo* foo2 = [[Foo alloc] init];
            [foos addObject:[WeakReferenceWrapper wrapNonretainedObject:foo2]];
            for (WeakReferenceWrapper* value in foos) {
                NSLog(@"%p", [value get]);
            }
        }
        for (WeakReferenceWrapper* value in foos) {
    

你可能感兴趣的:(iOS_OC)