正文
-
自己生成的对象自己持有
-
非自己生成的对象,自己也可以持有
-
不再需要自己持有的对象时释放
-
非自己持有的对象无法释放
__weak修饰符
仅仅通过__strong修饰符不能够解决引用计数内存管理中的“循环引用”问题。
例如:
@interface Test : NSObjecgt
{
id __strong obj_;
}
- (void) setObject:(id __strong)obj;
@end
@implementation Test
- (id) init
{
self = [super init];
return self;
}
- (void) setObject:(id __strong)obj
{
obj_ = obj;
}
@end
以下为循环引用:
{
id test0 = [[Test alloc] init];/* 对象A */
/*
* test0 持有Test对象A的强引用
*/
id test1 = [[Test alloc] init];/* 对象B */
/*
* test1 持有Test对象B的强引用
*/
[test0 setObject:test1];
/*
* Test对象A的obj_成员变量持有Test对象B的强引用
* 此时,持有Test对象B的强引用的变量为Test对象A的obj_和test1
*/
[test1 setObject:test0];
/*
* Test对象B的obj_成员变量持有Test对象A的强引用
* 此时,持有Test对象A的强引用的变量为Test对象B的obj_和test0
*/
}
/*
* 因为test0变量超出其作用域,强引用失效,所以自动释放Test对象A
* 因为test1变量超出其作用域,强引用失效,所以自动释放Test对象B
* 此时持有Test对象A的强引用的变量为Test对象B的obj_
* 此时持有Test对象B的强引用的变量为Test对象A的obj_
* 发生内存泄漏
*/
循环引用容易发生内存泄漏。内存泄漏就是应当废弃的对象在超出其生存周期后继续存在。
以下代码也会引起内存泄漏(对自身的强引用)
id test = [[Test alloc] init];
[test setObject:test];
使用__weak修饰符可以避免循环引用。
__weak修饰符与__strong修饰符相反,提供弱引用。弱引用不能持有对象实例。
id __weak obj = [[NSObject alloc] init];
如果运行以上代码,编译器会发出警告。
Assigning retained object to weak variable; object will be released after assignment
以上代码将自己生成并持有的对象赋值给附有__weak修饰符的变量obj。即变量obj持有对持有对象的弱引用。因此,为了不以自己持有的状态来保存自己生成并持有的对象,生成的对象会被立即释放。如果将对象赋值给附有__strong修饰符的变量之后再赋值给附有__weak修饰符的变量,就不会发生警告了。
{
/**自己生成并持有对象*/
id __strong obj0 = [[NSObject alloc] init];
/** 因为obj0变量为强引用,所以自己持有对象 */
id __weak obj1 = obj0;
/** obj1变量持有生成对象的弱引用 */
}
/*
*因为obj0变量超出其作用域,强引用失效,所以自动释放自己持有的对象。
*因为对象的所有者不存在,所以废弃该对象。
*/
因为带__weak修饰符的变量(弱引用)不持有对象,所以在超出其变量作用域时,对象即被释放。如下代码即可避免循环引用。
@interface Test : NSObject
{
id __weak obj_;
}
- (void) setObject:(id __strong) obj;
@end
__weak修饰符还有另一优点:在持有某对象的弱引用时,若该对象被废弃,则此弱引用将自动失效且处于nil被赋值的状态(空弱引用)。如下所示:
id __weak obj1 = nil;
{
/**自己生成并持有对象*/
id __strong obj0 = [[NSObject alloc] init];
/**因为obj0变量为强引用,所以自己持有对象*/
obj1 = obj0;
/**obj1持有对象的弱引用*/
NSLog(@"A: %@",obj1);
/** 输出obj1变量持有的弱引用的对象*/
}
/*
*因为obj0变量超出其作用域,强引用失效,所以自动释放自己持有的对象。
*因为对象无持有者,所以废弃该对象。
*废弃对象的同时,持有该对象弱引用的obj1变量的弱引用失效,nil赋值给obj1.
*/
NSLog(@"B: %@",obj1);
/** 输出赋值给obj1变量中的nil */
该代码的运行结果为:
2017-12-05 20:13:28.458858+0800 ImageOrientation[6316:1604800] A: <NSObject: 0x604000207710>
2017-12-05 20:13:30.112086+0800 ImageOrientation[6316:1604800] B: (null)
以上,使用__weak修饰符可以避免循环引用。通过检查__weak修饰符的变量是否为nil,可以判断被赋值的对象是否以废弃。