您的位置:首页 > Web前端

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

2017-03-07 18:28 567 查看
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) {

    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐