永发信息网

解释arc原理,arc引入之后,ios增加了几个修饰符,分别是什么?并解释何时应该使用

答案:1  悬赏:20  手机版
解决时间 2021-02-20 03:22
解释arc原理,arc引入之后,ios增加了几个修饰符,分别是什么?并解释何时应该使用
最佳答案
ARC的本质
ARC是编译器(时)特性,而不是运行时特性,更不是垃圾回收器(GC)。
Automatic Reference Counting (ARC) is a compiler-level feature that simplifies the process of managing object lifetimes (memory management) in Cocoa applications.
ARC只是相对于MRC(Manual Reference Counting或称为非ARC,下文中我们会一直使用MRC来指代非ARC的管理方式)的一次改进,但它和之前的技术本质上没有区别。具体信息可以参考ARC编译器官方文档。
ARC的开启与关闭
不同于XCode4可以在创建工程时选择关闭ARC,XCode5在创建的工程是默认开启ARC,没有可以关闭ARC的选项。
如果需要对特定文件开启或关闭ARC,可以在工程选项中选择Targets -> Compile Phases -> Compile Sources,在里面找到对应文件,添加flag:
打开ARC:-fobjc-arc
关闭ARC:-fno-objc-arc
如图:

ARC的修饰符
ARC主要提供了4种修饰符,他们分别是:__strong,__weak,__autoreleasing,__unsafe_unretained。
__strong
表示引用为强引用。对应在定义property时的"strong"。所有对象只有当没有任何一个强引用指向时,才会被释放。
注意:如果在声明引用时不加修饰符,那么引用将默认是强引用。当需要释放强引用指向的对象时,需要将强引用置nil。
__weak
表示引用为弱引用。对应在定义property时用的"weak"。弱引用不会影响对象的释放,即只要对象没有任何强引用指向,即使有100个弱引用对象指向也没用,该对象依然会被释放。不过好在,对象在被释放的同时,指向它的弱引用会自动被置nil,这个技术叫zeroing weak pointer。这样有效得防止无效指针、野指针的产生。__weak一般用在delegate关系中防止循环引用或者用来修饰指向由Interface Builder编辑与生成的UI控件。
__autoreleasing
表示在autorelease pool中自动释放对象的引用,和MRC时代autorelease的用法相同。定义property时不能使用这个修饰符,任何一个对象的property都不应该是autorelease型的。
一个常见的误解是,在ARC中没有autorelease,因为这样一个“自动释放”看起来好像有点多余。这个误解可能源自于将ARC的“自动”和autorelease“自动”的混淆。其实你只要看一下每个iOS App的main.m文件就能知道,autorelease不仅好好的存在着,并且变得更fashion了:不需要再手工被创建,也不需要再显式得调用[drain]方法释放内存池。

以下两行代码的意义是相同的。
NSString *str = [[[NSString alloc] initWithFormat:@"hehe"] autorelease]; // MRC
NSString *__autoreleasing str = [[NSString alloc] initWithFormat:@"hehe"]; // ARC

这里关于autoreleasepool就不做展开了,详细地信息可以参考官方文档或者其他文章。
__autoreleasing在ARC中主要用在参数传递返回值(out-parameters)和引用传递参数(pass-by-reference)的情况下。
__autoreleasing is used to denote arguments that are passed by reference (id *) and are autoreleased on return.
比如常用的NSError的使用:
NSError *__autoreleasing error;
if (![data writeToFile:filename options:NSDataWritingAtomic error:&error])
{
  NSLog(@"Error: %@", error);
}
(在上面的writeToFile方法中error参数的类型为(NSError *__autoreleasing *))
注意,如果你的error定义为了strong型,那么,编译器会帮你隐式地做如下事情,保证最终传入函数的参数依然是个__autoreleasing类型的引用。

NSError *error;
NSError *__autoreleasing tempError = error; // 编译器添加
if (![data writeToFile:filename options:NSDataWritingAtomic error:&tempError])
{
  error = tempError; // 编译器添加
  NSLog(@"Error: %@", error);
}

所以为了提高效率,避免这种情况,我们一般在定义error的时候将其(老老实实地=。=)声明为__autoreleasing类型的:
NSError *__autoreleasing error;

在这里,加上__autoreleasing之后,相当于在MRC中对返回值error做了如下事情:
*error = [[[NSError alloc] init] autorelease];

*error指向的对象在创建出来后,被放入到了autoreleasing pool中,等待使用结束后的自动释放,函数外error的使用者并不需要关心*error指向对象的释放。
另外一点,在ARC中,所有这种指针的指针 (NSError **)的函数参数如果不加修饰符,编译器会默认将他们认定为__autoreleasing类型。
比如下面的两段代码是等同的:
- (NSString *)doSomething:(NSNumber **)value
{
// do something
}
- (NSString *)doSomething:(NSNumber * __autoreleasing *)value
{
// do something
}

除非你显式得给value声明了__strong,否则value默认就是__autoreleasing的。
最后一点,某些类的方法会隐式地使用自己的autorelease pool,在这种时候使用__autoreleasing类型要特别小心。
比如NSDictionary的[enumerateKeysAndObjectsUsingBlock]方法:

- (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error
{
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){

// do stuff
if (there is some error && error != nil)
{
*error = [NSError errorWithDomain:@"MyError" code:1 userInfo:nil];
}

}];
}

会隐式地创建一个autorelease pool,上面代码实际类似于:

- (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error
{
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){

@autoreleasepool // 被隐式创建
      {
if (there is some error && error != nil)
{
*error = [NSError errorWithDomain:@"MyError" code:1 userInfo:nil];
}
 }
}];

// *error 在这里已经被dict的做枚举遍历时创建的autorelease pool释放掉了 :(
}

为了能够正常的使用*error,我们需要一个strong型的临时引用,在dict的枚举Block中是用这个临时引用,保证引用指向的对象不会在出了dict的枚举Block后被释放,正确的方式如下:

- (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error
{
  __block NSError* tempError; // 加__block保证可以在Block内被修改
  [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop)
  {
    if (there is some error)
    {
      *tempError = [NSError errorWithDomain:@"MyError" code:1 userInfo:nil];
    } 

  }]

  if (error != nil)
  {
    *error = tempError;
  } 
}
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
搬新房注意事项
下列有关细胞癌变的叙述,正确的是CA. 基因突
中国人寿保险股份有限公司泗阳支公司我想知道
我的魅族x5别人打电话过来只有铃声没有显示
我妈妈骑电动车过马路没有走斑马线,被酒驾撞
100米冠军尤塞恩·博尔特 怎么这么牛
康自斌中医诊所地址在什么地方,想过去办事
原味发酵乳是要冲水喝吗
急急急!刚买的新车声音咋那么大 尤其是加油
铁观音用锡罐装好还是瓷罐好
捷安特清徐专卖店怎么去啊,有知道地址的么
【赵孟頫怎么读】中国四大书法家赵孟頫的頫怎
微信聊天 女孩为什么对我呵呵、嗯嗯、没、怎
保基苗族彝族乡地址有知道的么?有点事想过去
形容一个人很有想像力的词语
推荐资讯
4.5.8.9列综合算式结果为24
聚宾烧烤地址在什么地方,想过去办事
自己家用的卫生间 ,还是坐式的马桶,不想接
慕斯蛋糕冰箱能放多久
凤岭·新家园双语艺术幼儿园我想知道这个在什
一个数的2.5倍减去3.2与4的积,差是19.2,求这
红米手机有没有来电闪光功能
1991年农历2月初9,下午5点多出生的女孩命运线
日本漫画 王国少主和千人斩武士
沈阳浑南新区文源街在哪
花草太阳神有旺财作用吗
做事情一定要有兴趣才能做好吗?
正方形一边上任一点到这个正方形两条对角线的
阴历怎么看 ?