[翻译]Transitioning to ARC Release Notes中文版

http://transideology.com/2015/09/%E7%BF%BB%E8%AF%91transitioning-to-arc-release-notes/


模式下运行。鉴于 @autoreleasepool 比 NSAutoreleasePool 快如此之多,一些老的性能优化小技巧可以被简单的替换成 @autoreleasepool方式了。

转换器可以处理一些简单的 NSAutoreleasePool使用,对于一些复杂的情况,或者定义在新的@autoreleasepool然后被后面代码使用的变量,转换器都无法自动处理。

  • ARC要求你在 init 方法中调用 [super init] ,并将返回值赋给 self

下面例子使用 init 在ARC模式下是不正确的

[super init];

简单的修复一下

self = [super init];

合适的方法是

self = [super init];
if (self) {
   ...
  • 你不能实现自定义 retain 和 release 方法

实现自定义 retain 和 release 方法会破坏weak指针,下面是一些你希望提供自定义retain 和 release 方法的常见原因(译者注:这里指的是过去MRC,并不意味着在ARC时代你可以自定义这两个方法)。

1、性能原因

请不要再这么做的,因为 NSObject 对象的 retain 和 release 方法更加快了。如果你还是发现有问题,请提交bug给我们处理。

2、实现自定义的weak指针

请直接使用 __weak

3、实现一个单例

请使用共享的实例设计模式。除此之外,请使用类方法而不是实例方法,这样可以避免分配对象。(译者注:我理解共享实例设计模式是,单例的最终实例对象是被一个全局的static指针指向的,当每次获取单例的对象时,使用类的方法调用,而不是实例的方法,这样避免了每次对象分配,只需要第一次在类方法中多线程安全的alloc一次。)

  • 被赋值(assigned)实例变量是strong引用的

在ARC之前,实例变量是不拥有对对象的引用的——直接把一个对象赋值给实例变量是不能增加对象的生命周期的(译者注:即不能增加对象的引用基数,因为在MRC时代需要主动调用retain,或者根据命名规范,一些new开头、alloc等方法会增加引用计数)。为了产生一个strong属性(译者注:这里仍然指的是MRC时期),你需要实现或生成存取器方法(accessor methods),在这些方法内部去调用合适的内存管理方法。而对于weak属性,你需要像下面的例子所展示的那样去实现存取器方法来管理weak属性。(译者注:下面代码是MRC的,我理解MRC没有weak属性的,只是默认需要手动retain才会增加对象的引用计数,所有不调用retain就相当于一个weak引用,但并没有ARC下weak指针自动nil的功能,这里等价于ARC中的__unsafe_unretained)

@interface MyClass : Superclass {
    id thing; // Weak reference.
}
// ...
@end
 
@implementation MyClass
- (id)thing {
    return thing;
}
- (void)setThing:(id)newThing {
    thing = newThing;
}
// ...
@end

而对于ARC,实例变量对于对象的引用默认是strong的——把一个对象直接赋值给实例变量会增加对象的生命周期(译者注:即增加了对象的引用计数)。代码转换工具并不能判断到底哪个变量是被特意设计成weak的。所以你需要把那些你想要设计成weak引用的实例变量主动标记为weak。

@interface MyClass : Superclass {
    id __weak thing;
}
// ...
@end
@implementation MyClass
- (id)thing {
    return thing;
}
- (void)setThing:(id)newThing {
    thing = newThing;
}
// ...
@end

或者

@interface MyClass : Superclass
@property (weak) id thing;
// ...
@end
@implementation MyClass
@synthesize thing;
// ...
@end
  • 在C结构体中不能使用strong  ids

如下代码无法通过编译

struct X { id x; float y; };

因为 x 默认是strong引用,编译器无法安全可靠的生成让它正确工作所需要的所有代码。例如,你将一个指向结构体的指针传递到一段在结尾处会 free 这个结构体的代码,每一个 id 都必须在结构体 free 前被释放。编译器无法安全的生成这些额外的代码,所以在ARC模式下strong id是不允许的(译者注:不理解为何不能生成安全的代码,后面提到在c++类中可以使用)。以下是一些可行的解决方案

1、使用Objective-C对象来代替结构体

这个是最好的方案

2、如果不方便使用Objective-C(或许你想使用存放结构体的原生数组),可以考虑用 void*代替在结构体中定义id

这种方法要求显式转换(译者注:即使用Toll-Free bridging 中的三种方法)

3、将对象的引用关系标记为 __unsafe_unretained

这种方法在一些不怎么更改带有定义常量性质的结构体中很有用,

struct x { NSString *S;  int X; } StaticArray[] = {
  @"foo", 42,
  @"bar, 97,
...
};

你可以这样定义结构体

struct x { NSString * __unsafe_unretained S; int X; 

如果NString指针的对象被释放的话,用这种方法可能不安全,但是如果你确定这些结构体是用来像常量一样来保存一些不变的东西的话,这么做还是很有用的。

  •  你不能直接在 id 和 void*之间做转换(包括Core Foundation 类型)(译者注:这里直接指的是隐式转换)

详细内容可以参考 Managing Toll-Free Bridging.(译者注:可以使用bridge的三种方法转换。)

 

经常被问到的一些问题

我应该怎么看待ARC?它在哪里增加了 retains/release?

尝试不要再去思考 retain/release 被自动添加到哪里了,多去思考一下你程序的算法吧。思考你的对象的strong和weak指针以及对象之间的关系,避免retain cycle的问题。

我是否还需要为对象写 dealloc 方法

或许需要

因为ARC并不自动执行 malloc/free操作,也不管理Core Foundation对象、文件和其他一些对象的生命周期,所以你仍然需要写一个 dealloc 来去释放这些资源。

你不应该也不能够去释放一个实例变量,但是你可能需要在系统类上调用 [self setDelegate:nil]。

在ARC模式下,dealloc 中不允许调用[super dealloc],运行时库会负责维护这条继承链的调用的。

ARC中是否还存在 retain cycles

存在

ARC其实是自动调用 retain/release,所以同样的问题仍然存在。幸运的是,ARC代码中很少出现泄漏问题,因为属性已经声明了是否需要被retained。(译者注:即可以在适当的地方声明为weak引用)

ARC中的block是如何工作的

Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. You don’t have to call Block Copy any more.(译者注:由于对block理解不深,这里不做翻译,大家自己理解吧。待以后详细研究了block再做翻译。)

不过你需要注意的一件事情是,在ARC下使用 NSString * __block myString时,myString是被retained,如果想要之前的效果(译者注:在MRC使用__block是,除了表明变量在block中可以修改,也表明变量不会被自动retained,即block对象不会增加变量的引用计数),请使用__block NSString * __unsafe_unretained myString 或者最好使用  __block NSString * __weak myString.。

我可以在Snow Leopard版本的系统上使用ARC吗?

不可以,因为Snow Leopard系统上的Xcode4.2不支持ARC,这个系统没有包含10.7的SDK。Snow Leopard上的Xcode4.2也不支持iOS,Lion系统的Xcode4.2支持iOS和OS X。这意味这你需要Lion系统来编译ARC代码。

在ARC模式下,我可以创建一个C Array,里面retain 对象的引用吗?

可以的,代码如下

// Note calloc() to get zero-filled memory.
__strong SomeClass **dynamicArray = (__strong SomeClass **)calloc(entries, sizeof(SomeClass *));
for (int i = 0; i < entries; i++) {
     dynamicArray[i] = [[SomeClass alloc] init];
}

// When you're done, set each entry to nil to tell ARC to release the object.
for (int i = 0; i < entries; i++) {
     dynamicArray[i] = nil;
}
free(dynamicArray);

不过要注意一些问题

  • 要使用__strong SomeClass ** ,因为如果不使用strong,ARC默认生成的是__autoreleasing SomeClass **。(见上文提交的NSError的代码)
  • 分配的内存填充的必须是0
  • 释放array前你必须把array中的每个元素都赋值为 nil (memset 或 bzero 是无效的)。
  • 你应该避免使用 memcpy or realloc

ARC慢吗?

这样看你指的哪方面,通常情况下答案是否定的。编译器会高效的删除许多没有必要的retain/release,我们也做了很多努力来提升Objective-C运行时库的速度。尤其是,常用的“返回 retain/autoreleased 对象”的模式在ARC下是非常的快的,当调用这样的方法的时候,并不真的把对象放在自动释放池里。(译者注:具体怎么做求大神指点)

需要注意的一个问题是,在debug模式下优化是不生效的,所有想要看到一些ARC的技术细节应该使用编译选项-O0 而不是-Os

ARC在ObjC++模式下生效吗?

是生效的。你甚至可以在类和容器中使用strong/weak ids 。ARC编译器会在拷贝构造函数和析构函数中生成retain/release 调用的代码。

那些类不支持weak引用?

目前NSATSTypesetterNSColorSpaceNSFontNSMenuViewNSParagraphStyle,NSSimpleHorizontalTypesetter, and NSTextView.这些类不能被创建使用weak指针来引用的实例。

注意:除此之外,在OS X10.7上不能创建NSFontManagerNSFontPanelNSImage,NSTableCellView,NSViewControllerNSWindow, and NSWindowController的弱引用实例。OS X10.7上AV Foundation中的类都不能用弱引用。

对于这些类,如果是当作属性使用的话,可以使用来assign 代替weak。如果是定义为变量的话可以使用__unsafe_unretained 。除此之外NSHashTableNSMapTable, orNSPointerArray 也不能用弱引用。

如果我要子类化NSCell或者子类化其他使用NSCopyObject的类,我应该怎么做?

请正常使用,没有什么特别的地方。对于你之前要显示调用retain的地方,ARC会负责处理的。在ARC模式下,所有的copy方法都应该仅仅是浅拷贝。(这里原文是all copy methods should just copy over the instance variables.  翻译的是否正确有待第二次校验。)

我是否可以指定一些文件不使用ARC

可以的。

当你把一个工程转换成ARC时,所有的Objective-C原文件都默认使用-fobjc-arc 编译选项。你可以使用-fno-objc-arc 编译选项来对一些类关闭ARC。(译者注:这里去掉了设置步骤,因为文章是2013年的,目前2015的Xcode7已经和当时差异很大了。我不会告诉你我是翻译累了不想写了。)

在Mac上GC(Garbage Collection)被弃用了吗?

在OS X Mountain Lion v10.8上GC已经被弃用了,在以后的版本中也不再会使用。ARC是推荐的技术,为了转化已有的工程,Xcode 4.3和以后版本中的转化工具会帮助Mac程序从GC迁移到ARC模式的。

注意:对于Mac程序,Apple强烈建议尽快从GC转化为ARC方式,因为Mac应用市场规范禁止使用废弃的技术。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值