综述:

在项目中使用 ARC之后,所有的编程都和以前一样,除了你不再调用 retain, release, autorelease。启用 ARC 之后,编译器会自动在适当的地方插入retain, release, autorelease 语句。

ARC 的规则:

只要还有一个变量指向对象,对象就会保存在内存中。

ARC 的限制:

ARC 只能工作于 Objective-C 对象,如果 应用使用了 Core Foundation 或 malloc()/free(),此时需要你来管理内 存。

“strong”指针和“weak”指针:

“strong”指针:能够保持对象的生命。

因为 strong 指针会保持对象的生命,某些情况下你需要手动设置这些指针为 nil,否则可能导致应用内存不足。

(默认所有实例变量和本地变量都是 strong 类型的指针,一般strong 变量不加 __strong 修饰。)

“weak”指针:weak 变量仍然指向一个对象,但不是对象的拥有者,“weak”指针所指内容被释放时,“weak”指针会被自动置为nil.

典型的例子是 delegate 模式:

(你的ViewController通过strong指针拥有一个UITableView, TableView 的 data source 和 delegate 都是weak指针,指向ViewController)。

对象之间的关联:

启用ARC之后,不再需要考虑什么时候 retain 或 release 对象。唯一需要考虑的是对象之间的关联,谁拥有该对象,以及这个对象需要存活多久。

一个例子:

以下代码在 ARC 之前是不可能的,在手动内存管理中,从 Array 中 移除一个对象会使对象不可用,对象不属于Array 时会立即被释放。随后 NSLog()打印该对象就会导致应用崩溃。

id obj =[array objectAtIndex:0];

[array removeObjectAtIndex:0];

NSLog(@"%@", obj);

在ARC 中,这段代码是完全合法的,因为 obj 变量是一个 strong 指针, 它成为了对象的拥有者,从 Array 中移除该对象也不会导致对象被释放。

ARC 的迁移:

要启用一个项目的 ARC,你有以下几种选择:

1. Xcode 带了一个自动转换工具,可以迁移源代码至 ARC


2. 你可以手动转换源文件


3. 你可以在 Xcode 中禁用某些文件使用 ARC,这点对于第三方库非常有用。

Xcode 的自动迁移工具:

1, ARC 是 LLVM3.0编译器的特性,而现有工程可能使用老的 GCC4.2 或 LLVM-GCC编译器,因此首先需要设置使LLVM 3.0 编译器。

Project Settings -> target -> Build Settings,在搜索框中输入 compiler, 就可以列出编译器选项设置:

另外最好也选上 Warnings 中的 Other Warning Flags 为 -Wall,这样编译 器就会检查所有可能的警告,有助于我们避免潜在的问题。

同样,Build Options 下面的 Run Static Analyzer 选项也最好启用,这样 每次 Xcode 编译项目时,都会运行静态代码分析工具来检查我们的代码。

2,  Build Settings 下面,选择“All”,搜索框输入"automatic",可以设置 "Objective-C Automatic Reference Counting"选项为 Yes,不过 Xcode 自动转 换工具会自动设置这个选项。

3,  Xcode 的 ARC 自动转换工具: Edit->Refactor->Convert to Objective-C ARC

4,  选择需要转换的文件,Xcode 可能会提示项目不能转换为 ARC。此时:

打开 Xcode Preferences 窗口,选择 General 标签,启用 Continue building after errors 选项,再次执行 Edit\Refactor\Convert to Objective-C ARC:

5,        再有错误的情况下,就需要手工修改某些源代码。

注意:Xcode 的自动转换工具最好只使用一次。多次使用可能会出现比较诡异的问题。假如你第一次转换没有转换所有的文件,当你稍后试图再次转换剩余的 文件时,Xcode 实际上不会执行任何转换操作。因此最好一次就完成转换,没有 转换的文件可以考虑手工进行修改。

禁止某些文件的ARC:

最简单的方法是直接使用 Xcode 的 ARC 转换工具,取消选中那些不希望 进行ARC转换的源文件,这样Xcode会自动对这些文件设置 -fno-objc-arc标 志。

手动修改:对于某些我们不希望使用 ARC 的文件,例如第三方库源文件,可以在 Project Settings -> Build Phases 中,对这些文件选中 -fno-objc-arc 标志。

另外,可以使用预处理指令在必要时保持与 ARC 兼容:

#if _has_feature(objc_arc)

  //do your ARC thing here

#endif

  或者假如你还想支持老的 GCC compiler:

#if defined(_has_feature )&& _has_feature(objc_arc)

  //do your ARC thing here

#endif

ARC 自动迁移的常见问题:

1,"Switch case is in protected scope"

switch (x)

{

case Y:

  NSString *s =…;

  Break;

}

ARC 不允许这样的代码,指针变量需要定义在 switch 语句外面,或者使用{}定义一个新的块:

switch (x)

{

case Y:

{

  NSString *s =…;

  Break;

}

}

这样 ARC 才能确定变量的作用域,从而在适当的时候释放该变量。

2,"ARC forbids Objective-C objects in structs or unions"

使用 ARC 之后,C Struct 中不能使用 Objective-C 对象, 解决办法是定义一个 Objective-C 类,不使用 C Struct。

Property总结:

  • strong:等同于"retain",属性成为对象的拥有者
  • weak:属性是 weak pointer,当对象释放时会自动设置为 nil,记住 Outlet 
应该使用 Weak
  • unsafe_unretained:等同于之前的"assign",只有 iOS 4 才应该使用。

(unsafe_unretained 指针和 weak 指针不一样的是,当相关联的对象释放时, 指针不会被设置为 nil,因此它实际上指向不存在的对象。)

dealloc 方法:

启用 ARC 之后,dealloc 方法在大部分时候都不再需要了。如果你的 dealloc 方法处理了其它资源(非内存)的释放,如定时器、Core Foundation 对象,则你仍然需要在 dealloc 方法中进行手动释放,如 CFRelease(), free()等。

Toll-Free Bridging:

当你在 Objective-C 和 Core Foundation 对象之间进行转换时,就需要使用 Bridge cast。(比如CFStringRef与NSString)

  • 使用 CFBridgingRelease(),从 Core Foundation 传递所有权给 Objective-C;
  • 使用 CFBridgingRetain(),从 Objective-C 传递所有权给 Core Foundation;
  • 使用__brideg,表示临时使用某种类型,不改变对象的所有权。

iOS 4 中使用 ARC:

ARC 主要是 LLVM 3.0 编译器(而不是 iOS 5)的新特性,因此你也可以在 iOS 4.0之后的系统中使用ARC,不过需要注意的是,weak 指针需要iOS5才能使用。 如果你要在 iOS 4 中部署 ARC 应用,你就不能使用 weak property 和__weak 变 量。

ARC 高级指南:

1,Blocks 与 ARC。(指南里面用了很大的篇幅讲解)

2,Singleton 与 ARC。

3,Cocos2D 和 Box2D。

4,Autorelease 和 AutoreleasePool。

ARC 仍然保留了 AutoreleasePool,但是采用了新的 Block 语法:@autoreleasepool.

在 ARC 中,方法名如果以 alloc, init, new, copy, mutableCopy 开头,就是返回 retain 的对象,其它方法全部返回 autorelease 的对象。这条规则实际 上与手动内存管理是一样的。

autorelease 对象则是在 autorelease pool 排干( drain ) 时才会被释放。在 ARC 之前,你需要调用 NSAutoreleasePool 对象的 [drain] 或 [release] 方法,现在则是直接在 @autoreleasepool 块退出时进行 drain:

@autoreleasepool

{

   NSString *s = [NSString stringWithFormat:…];

}// the string object is deallocated here

但是如果你像下面这样编写代码,则即使 NSString 对象在@autoreleasepool 块中创建,stringWithFormat:方法也确实返回了一个 autorelease 对象,但变 量 s 是 strong 类型的,只要 s 没有退出作用域,string 对象就会一直存在:

NSString *s;

@autoreleasepool

{

   s = [NSString stringWithFormat:…];

}// the string object is still alive here

使用 __autoreleasing 可以使 autorelease pool 释放掉该对象,它告诉编 译器这个变量指向的对象可以被 autorelease,此时变量不是 strong 指针, string 对象会在@autoreleasepool 块的末尾被释放。不过注意变量在对象释放后,仍然会继续指向一个死掉的对象。如果你继续使用它,应用就会崩溃。代码如下:

_autoreleasing NSString *s;

@autoreleasepool

{

   s = [NSString stringWithFormat:…];

}// the string object is deallocated here

NSLog(@”%@”,s);//crash!

注意 :Core Foundation 对象不能 autorelease , autorelease 完全纯属于 Objective-C。

posted on 2013-07-28 11:05  童话DY  阅读(432)  评论(0编辑  收藏  举报