Objective-C内存管理:从源码进行分析(二)

本文详细介绍了Objective-C中的自动引用计数(ARC)机制及其如何简化内存管理。特别是针对_strong修饰符的深入解析,包括其默认行为、如何在变量作用域内管理对象持有者,以及如何在赋值过程中正确管理对象持有者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通过对《Objective-C高级编程》的学习,就来总结一下。

解读

相信很多学习iOS编程的人都会认识ARC(自动引用计数),实际上呢,”引用计数内存管理”的本质部分在ARC中并没有改变。根据名字我们可以看出,ARC就是自动帮我们处理”引用计数”的相关部分而已。

从编译单位上的角度来讲,我们是可以对ARC进行有效或者无效的设置的。例如有一些文件可以使用ARC,有一些文章不可以使用ARC。

编译单元
ARC有效
ARC无效
ARC有效
ARC无效

从上面的表格我们就可以看出,一个应用程序可以混合ARC有效或者无效的二进制形式

Xcode 4.2以上默认设定为所有ARC有效

内存管理的思考方式

引用计数的思考方式就是思考ARC所引起的变化

  • 自己生成的对象,自己所持有
  • 非自己生成的对象,自己也能持有。
  • 自己持有的对象不需要时释放。
  • 非自己持有的对象无法释放。

所有权修饰符

Objectve-C编程中为了处理对象,我们可以将对象定义为id类型或者各种对象类型。

定义中这么写到:所谓的对象类型就是指向NSObject这样的Objectve-C类的指针,例如”NSObject”。id类型用于隐藏对象类型的类名部分,是不是有点像c语言的”void * “。

ARC有效的时候,id类型和对象类型同C语言其他类型不同,其类型上必须附加所有权修饰符。所有权修饰符一共有4种。

  • _strong修饰符
  • _weak修饰符
  • _unsafe_unretained修饰符
  • _autoreleaing修饰符

_strong修饰符

现在就来总结一下_strong修饰符的相关东西

_strong其实是id类型和对象类型的默认所有权修饰符。观察一下下面的源码,我们刚才提过,_strong是默认的所有权修饰符,ok,那么在下面的id变量中,实际上被附加了所有权修饰符。

id obj = [[NSObject alloc] init];

id和对象类型在没有明确指定所有权修饰符的时候,默认就是_strong。明确的格式为:

id _strong obj = [[NSObject alloc] init];

对比一下在ARC无效的时候,以上代码是如何表示的。

/* ARC无效 */

id obj = [[NSObject alloc] init];

看到了以上源代码,其实并没有发现什么不同。接着看另一组代码。

{
    id _strong obj = [[NSObject alloc] init];
}

此源代码明确指出了C语言变量的作用域。ARC无效的时,该源代码可记录如下:

{
    id _strong obj = [[NSObject alloc] init];

    [obj release];
}

为了释放生成秉并持有的对象,调用了release方法。该源代码进行的动作同先前ARC有效时的动作完全一样。

如此源代码所示,附有_strong修饰符的变量obj在其超出变量的作用域的时候,就是所在该变量被废弃的时候,会释放其被赋予的对象。

就像”strong”这个单词一样,_strong表示”强引用”。持有强引用的变量在超出其作用域的时候被废弃,随着强引用的失效,那么引用的对象也会被随之释放。

看一下对象的所有者部分:

id _strong obj = [[NSObject alloc] init];

这段代码很熟悉吧,这就是我们之前生成并持有对象的源代码,该对象的所有者如下:

{
    //自己生成并持有对象

   id _strong obj = [[NSObject alloc] init];

   //因为变量obj为强引用,所以自己持有对象。
}
  //在这片区域因为超出了其作用域,强引用失效。
  //所以自动地释放掉自己的持有的对象
  //对象的持有者不存在,所以废弃掉该对象。

在此之外,对象的所有者和对象的生命周期是明确的。那么取得非自己生成并持有的对象时又会怎么样呢?

{
    id _strong obj = [NSMutableArray array];
}

在NSMutableArray类的array类方法取得的源代码中取得非自己生成并持有的对象,具体做法如下:

{
    //自己生成并持有的对象

    id _strong obj = [NSMutableArray array];

    //因为变量obj为强引用
    //所以自己持有对象
}

  //变量obj超出作用域,强引用失效。
  //自动释放自己所持有的对象。

_strong变量之间是可以互相赋值的。

看以下代码:

id _strong obj0 = [[NSObject alloc] init];
id _strong obj1 = [[NSObject alloc] init];
id _strong obj2 = [[NSObject alloc] init];

obj0 = obj1;
obj2 = obj0;
obj0 = nil;
obj1 = nil;
obj2 = nil;

接下来我们来看一下生成并持有对象的强引用。

id _strong obj0 = [[NSObject alloc] init]; //对象A,obj0持有A的强引用
id _strong obj1 = [[NSObject alloc] init]; //对象B,obj1持有B的强引用

id _strong obj2 = nil; //obj2不持有任何对象。

obj0 = obj1;
//obj0持有由obj1赋值对象B的强引用
//因为obj0被赋值,原来持有的对象A的强引用失效
//对象A的持有者不存在,因此废弃掉对象A

//此时对象B的强引用变为obj0和obj1

obj2 = obj0;

//obj2持有由obj0赋值的对象B的强引用。

//此时持有对象B的强引用变为obj0,obj1,obj2.

obj1 = nil//因为obj为nil,所以对B的强引用失效。

//此时,持有B的强引用位obj0和obj2。


obj0 = nil//因为obj0位nil,所以对对象B的强引用失效
//此时持有对象B的强引用为obj2

obj2 = nil//因为obj2为nil
//对象B的持有者不存在所以废弃掉对象B

通过上面的例子我们可以看出来,_strong不仅可以在变量作用域中有效的管理对象的持有者,在赋值中也可以正确的管理对象的持有者。

当然,即便Objective-C类成员变量,也可以在方法参数上,使用附有_strong修饰符的变量。

@interface Test : NSObjet
{
    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 _strong test = [[Test alloc] init];
    [test setObject ;[[NSobject alloc] init]];
}

该例子生成并持有对象的状态记录如下:


{
    id _strong test = [[Test alloc] init];
    //Test持有test对象的强引用

    [test setObject:[[NSobject alloc] init]];

    //Test对象的obj_成员,
    //持有NSobject对象的强引用。
}
    //test超出作用域,强引用失效
    //自动释放Test
    //Test对象的所有者不存在,因此废弃掉该对象。

    //废弃掉Test对象的同时。
    //Test对象的obj_成员也被废弃掉。
    //NSObject对象的强引用失效
    //自动释放NSObject对象
    //NSObject对象的所有者不存在,因此废弃掉该对象

ok,就这样无需做额外的工作便可以适用于类成员方法及方法参数中。

正如苹果宣称的那样,通过_strong修饰符,不需要在键入retain或者是release,完美的满足了”引用计数内存管理的思考方式”:

  • 自己生成的对象,自己所持有
  • 非自己生成的对象,自己也能持有。
  • 自己持有的对象不需要时释放。
  • 非自己持有的对象无法释放。

引用书中的话进行介绍就是:

前两项”自己生成的对象,自己持有”和非自己生成的对象,自己也能持有”,通过对象_strong修饰符变量的赋值便可以达成。通过废弃_strong修饰符的变量或者对变量赋值,都可以做到”不再需要自己持有的对象时释放”。最后一项”非自己持有的对象无法释放”,由于不必在键入release,所以原本就不会执行。这都都满足”引用计数内存管理的思考方式”。

因为id类型和对象类型的所有权修饰符默认为_strong修饰符,所以不需要写上_strong。使用ARC有效及简单的编程遵循了Objective-C内存管理思考方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值