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)  initWithNonretainedObjec t:(id)obj;
-(id)  get;

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

@end

@implementation  WeakReferenceWrapper  {
        __weak  id  weakReference;
}

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

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

-(id)  initWithNonretainedObjec t:(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)  {
                        NSLog(@"%p",  [value  get]);
                }
        }
        return  0;
===========================================================
        一定要注意的是:如果WeakReferenceWrapper 指向的对象被析构了。WeakReferenceWrapper 对象本身不会设置为nil,而是get方法返回nil。这是因为容器类中保存的是WeakReferenceWrapper 强引用,WeakReferenceWrapper 保存的是对象的弱引用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值