专栏名称: 蚂蚁金服ProtoTeam
数据前端团队
目录
相关文章推荐
前端大全  ·  你以为的 Tailwind ... ·  20 小时前  
神兽集团  ·  美乱纪元开启第一集:问计! ·  昨天  
神兽集团  ·  美乱纪元开启第一集:问计! ·  昨天  
前端早读课  ·  【第3527期】Pinterest ... ·  2 天前  
51好读  ›  专栏  ›  蚂蚁金服ProtoTeam

Objective-C 内存管理之ARC规则

蚂蚁金服ProtoTeam  · 掘金  · 前端  · 2017-12-07 15:57

正文

请到「今天看啥」查看全文


  • 自己生成的对象自己持有
  • 非自己生成的对象,自己也可以持有
  • 不再需要自己持有的对象时释放
  • 非自己持有的对象无法释放

__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,可以判断被赋值的对象是否以废弃。







请到「今天看啥」查看全文