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) {