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) {
在项目中有某个功能需要用到多个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如何在数组中使用弱引用(weak reference)
- IOS如何在容器类(如NSMutableSet)…
- iOS开发学习专题-基础知识(二)NSArray数组NSMutableArray可变数组NSSet集合NSMutableSet可变集合详细使用方式
- iOS开发OC基础:OC集合NSSet、NSMutableSet以及NSCountedSet的基本方法的使用
- iOS使用NSMutableSet记录cell控件选中状态避免cell重用问题
- [ios] NSSet,NSMutableSet[zhuan]
- iOS开发OC基础:OC字典NSDictionary以及NSMutableDictionary基本方法的使用
- iOS之NSData与NSMutableData的使用
- 【IOS】如何封装结构体对象到NSMutableArray中
- iOS使用NSMutableAttributedString
- iOS使用NSMutableAttributedString 实现富文本(不同颜色字体、下划线等)
- iOS使用NSMutableAttributedString 实现富文本(不同颜色字体、下划线等)
- WeakReference (弱引用),配合GC使用,提高程序效率
- 集合:NSArray、NSMutableArray、NSDictionary、NSMutableDictionary、NSSet、NSMutableSet使用
- IOS 基础知识 Foundation-NSString和NSMutableString的使用
- C++中防止STL中迭代器失效——map/set等关联容器——vector/list/deque等序列容器—如何防止迭代器失效—即erase()的使用
- C++中防止STL中迭代器失效__map/set等关联容器vector/list/deque等序列容器_如何防止迭代器失效_即erase()的使用
- IOS 基础知识 Foundation-NSString和NSMutableString的使用
- iOS 中由数组 NSArray 与 NSMutableArray 的使用理解偏差引发的多宗血案
- iOS使用NSMutableAttributedString实现富文本