`
啸笑天
  • 浏览: 3465260 次
  • 性别: Icon_minigender_1
  • 来自: China
社区版块
存档分类
最新评论

iPhone开发之深入浅出 (7) — ARC总结

 
阅读更多

 

 

通过前面几篇文章的介绍,我想大家应该对ARC有了一个比较完整的理解。最后,我们来对ARC做一个总结,并把一些未涉及到的细节部分再深入讨论一下。

内存管理基本原则

内存管理的依循下面的基本原则
  • 自己生成的对象,那么既是其持有者
  • 不是自己生成的对象,也可成为其持有者(一个对象可以被多个人持有)
  • 如果不想持有对象的时候,必须释放其所有权
  • 不能释放已不再持有所有权的对象

    不管ARC有没有效,该原则始终存在。

所有权关键字

从代码上看,有ARC的代码和没有ARC的代码区别就在下面的几个关键字。

类似 NSObject* 的对象类型,或者 id 类型1,当ARC有效的时候,根据具体情况,这些关键字必须要使用2

  • __strong
  • __weak
  • __unsafe_unretained
  • __autoreleasing

    __strong是默认的修饰符。

    __weak修饰了一个自动nil的weak引用。

    __unsafe_unretained声明了一个不会自动nil的weak引用。当变量被释放,那么它就变成了一个野指针了。

    __autoreleasing 用来修饰一个声明为 (id *) 的函数的参数,当函数返回值时被释放。

接下来,我们结合下面ARC的使用准则,来看看一些使用ARC后的技术细节。

ARC使用准则

为了避免程序秒退的尴尬,ARC有效时,我们的代码必须遵循下面的准则。

  • 不能使用 retain/release/retainCount/autorelease
  • 不能使用 NSAllocateObject/NSDeallocateObject
  • 不能使用 NSZone
  • 不能明示调用dealloc
  • 内存管理相关的函数必须遵循命名规则
  • 使用@autoreleasepool代替NSAutoreleasePool
  • Objective-C 对象不能作为C语言结构体(struct/union)的成员
  • 【id】与【void*】之间需要明示cast

建议使用Objective-C的class来管理数据格式,来代替C语言的struct。不能隐式转换 id 和 void *。

让我们一个一个来分析

不能使用 retain/release/retainCount/autorelease

内存管理完全交给编译器去做,所以之前内存相关的函数(retain/release/retainCount/autorelease)不能出现在程序中。Apple的ARC文档中也有下面的说明。

ARC 有效后,不需要再次使用retain 和 release

如果我们在程序中使用这些函数,经得到类似下面的编译错误信息。

    error: ARC forbids explicit message send of ’release’
         [o release];
          ^ ~~~~~~~

不能使用 NSAllocateObject/NSDeallocateObject

生成并持有一个Objective-C对象的时候,往往像下面一样使用NSObject的alloc接口函数。

    id obj = [NSObject alloc];

实际上,如果我们看了GNUstep 中关于 alloc 的代码就会明白,实际他是使用 NSAllocateObject 来生成并持有对象实例的。换言之,ARC有效的时候,NSAllocateObject函数的调用也是禁止的。如果使用,也会遇到下面的编译错误。

    error: ’NSAllocateObject’ is unavailable:
        not available in automatic reference counting mode

同样,对象释放时使用的 NSDeallocateObject 函数也不能使用。

不能使用 NSZone

NSZone 是什么?NSZone 是为了防止内存碎片而导入的一项措施。Zone 是内存管理的基本单元,系统中管理复数的Zone。系统根据对象的使用目的,尺寸,分配其所属的Zone区域。以提高对象的访问效率,避免不必要的内存碎片。但是,现在的运行时系统(用编译开关 __OBJC2__ 指定的情况下)是不支持Zone概念的。所以,不管ARC是否有效,都不能使用 NSZone。

不能明示调用dealloc

不管是否使用ARC,当对象被释放的时候,对象的dealloc函数被调用(就像是C++中对象的析构函数)。在该函数中,需要做一些内存释放的动作。比如,当对象中使用了malloc分配的C语言内存空间,那么dealloc中就需要像下面一样处理内存的释放。

1
2
3
4
- (void) dealloc
{
    free(buffer_);
}

又或者是注册的delegate对象,观察者对象需要被删除的时候,也是在dealloc函数中动作。

1
2
3
4
- (void) dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

如果在ARC无效的时候,我们还要像下面一样,调用父类对象的dealloc函数。

1
2
3
4
- (void) dealloc
{
    [super dealloc];
}

但是当ARC有效的时候,[super dealloc];的调用已经被编译器自动执行,已经不需要我们明示调用了。如果你在代码中还这样写,难免遇到下面的错误。

    error: ARC forbids explicit message send of ’dealloc’
         [super dealloc];
          ^ ~~~~~~~

内存管理相关的函数必须遵循命名规则

iPhone开发之深入浅出 (3) — ARC之前世今生中,我们知道如果是 alloc/new/copy/mutableCopy/init 开头的函数,需要将对象所有权返回给调用端。这条规则不管ARC是否有效都应该被遵守。只是 init 开头的函数比较特殊,他只在ARC下有要求,而且异常苛刻。

init 开始的函数只能返回id型,或者是该函数所属的类/父类的对象类型。基本上来说,init函数是针对alloc函数的返回值,做一些初始化处理,然后再将该对象返回。比如:

    id obj = [[NSObject alloc] init];

再比如下面定义的函数就是不对的:

    - (void) initThisObject;

需要是下面这样:

    - (id) initWithObject:(id)obj;

另外,下面名为 initialize 的函数比较特殊,编译器将把它过滤掉,不按上面的规则处理。

使用@autoreleasepool代替NSAutoreleasePool

在ARC之下,已经不能在代码中使用 NSAutoreleasePool,我们之前写 main.m 文件的时候,往往像下面这样写。

1
2
3
4
5
6
    int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

而当ARC有效后,我们需要用@autoreleasepool代替NSAutoreleasePool。

1
2
3
4
5
6
int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

当编译器看到 @autoreleasepool 定义的块后会自动生成 NSAutoreleasePool 对象,并将需要的对象放入 AutoReleasePool 中,当出方块的定义范围时,pool 中的对象将被释放。

Objective-C 对象不能作为C语言结构体(struct/union)的成员

当我们设置ARC有效,并在C语言的结构体中定义Objective-C的对象时,将出现类似下面的编译错误。

1
2
3
struct Data {
    NSMutableArray *array;
};
    error: ARC forbids Objective-C objs in structs or unions
         NSMutableArray *array;
                         ^

由于 ARC 是将内存管理的细节委托给编译器来做,所以说编译器必须要管理对象的生命周期。而LLVM 3.0中不存在对单纯C语言构造体成员的内存管理方法。如果单纯是栈对象,利用进出栈原理,可以简单地维护对象的生命周期;而结构体是不行的,简单地理解,结构体没有析构函数,编译器自身不能自动释放其内部的 Objective-C 对象。

当我们必须在C语言的结构体中放入 Objective-C 对象的时候,可以使用 void* 转型,或者使用 __unsafe_unretained 关键字。比如下面:

1
2
3
struct Data {
    NSMutableArray __unsafe_unretained *array;
};

这样一来,该内存信息不在编译器内存管理对象内,仅仅是使用而已,没有对象的持有权。当然,对象所有权的持有者需要明确的管理他与该结构体的交互,不要引起不必要的错误3

【id】与【void*】之间需要明示cast

ARC 有效的时候,由于编译器帮我们做了内存管理的工作,所以我们不需要太担心。但是当与 ARC 管理以外的对象类型交互的时候,就需要特殊的转型关键字,来决定所有权的归属问题。

主要的转型关键字是:

关键字 解释
__bridge 单纯的类型转换,没有进行所有权的转移
__bridge_retained 类型转换是伴随所有权传递,转换前后变量都持有对象的所有权
__bridge_transfer 类型转换伴随所有权转移,被转换变量将失去对象的所有权

当我们在 Core Foundation 对象类型与 Objective-C 对象类型之间切换的时候,需要把握下面的因素:

  • 明确被转换类型是否是 ARC 管理的对象
    • Core Foundation 对象类型不在 ARC 管理范畴内
    • Cocoa Framework::Foundation 对象类型(即一般使用到的Objectie-C对象类型)在 ARC 的管理范畴内
  • 如果不在 ARC 管理范畴内的对象,那么要清楚 release 的责任应该是谁
  • 各种对象的生命周期是怎样的

题外话

Xcode 4.3带来的变化

最近随着 iOS 5.1 的推出,Xcode也推出了4.3版本。在该版本下,ARC 有效时的属性(@property) 定义的时候,如果不明确指定所有权关键字,那么缺省的就是 strong。而在 Xcode4.2 中,即使 strong 也要显示指定。

在 Xcode4.2 的时候,针对下面的代码,

1
2
3
4
5
6
7
// ARC 无效
@property (nonatomic, retain) NSString *string;

// --->

// ARC 有效
@property (nonatomic, strong) NSString *string;

而在 Xcode 4.3 中,我们可以这么做,

1
2
3
4
5
6
7
// ARC 无效
@property (nonatomic, retain) NSString *string;

// --->

// ARC 有效
@property (nonatomic) NSString *string;

ARC 代码自动变换

另外,Xcode 4.2开始,增加了旧代码向 ARC 代码自动转换的功能。有兴趣的朋友可以试试。位置是:

Edit->Refactor->Convert to Objective-C ARC…

为什么iOS中没有GC

我们已经知道ARC并不是GC(垃圾回收)了,那么,为什么iOS中不支持该机能呢?还特意搞出个ARC来。以下是我的分析:

  • 消耗CPU时间的处理尽量避免,以节约电池电量
  • GC执行的后,会停掉运行时库;这是最大的心结
  • 嵌入式设备本身内存就不是很大,如果GC不停的在后台运行,执行的频率会很高,严重影响性能
    • UI动画处理是iOS的一大卖点,而有了GC后可能会引起不必要的性能损失

1. 关于Objective-C对象的解释,可以参考iPhone开发入门(7)— 从C/C++语言到Objective-C语言

2. 当然,如果你不写,编译器会用缺省的值代替。具体见iPhone开发之深入浅出 (3) — ARC之前世今生中的描述。

3. 关于这一点,可以参考iPhone开发之深入浅出 (1) — ARC是什么 一文,明白为什么 __unsafe_unretained 是危险的。

 

 

from http://www.yifeiyang.net/development-of-the-iphone-simply-7/

分享到:
评论

相关推荐

    《iPhone应用程序开发攻略之深入浅出Objective-C 2.0》.(王志刚).[PDF]&ckook

    《iPhone应用程序开发攻略之深入浅出Objective-C 2.0》是王志刚撰写的一本专为iOS开发者设计的教程,旨在帮助读者掌握Objective-C 2.0编程语言,从而能够开发高质量的iPhone应用程序。Objective-C是苹果公司开发的...

    深入浅出iphone编程 (headfirst iphone development)11 chapter

    《深入浅出iPhone编程》是Head First系列中的一本专为初学者设计的iOS开发教程,专注于iPhone应用的开发。本书的第11章在前10章的基础上,继续深入探讨iOS开发的关键技术和实践,旨在帮助读者理解并掌握iPhone应用...

    深入浅出讲objective-c

    "深入浅出讲Objective-c"的文档很可能涵盖了这些内容,并可能包含更多关于类设计、异常处理、调试技巧等实际开发中的细节。通过学习这份文档,初学者可以系统地掌握Objective-C的基础知识,并逐步进入iOS和macOS应用...

    iPhone开发基础教程

    这本书深入浅出地介绍了如何使用苹果的Xcode集成开发环境(IDE)以及Objective-C编程语言来构建iPhone应用程序。 首先,iOS平台的基础知识是学习iPhone开发的起点。iOS是由苹果公司开发的操作系统,主要运行在...

    iphone 开发

    首先,本书深入浅出地讲解了Objective-C的基础知识,包括语法结构、类、对象、消息传递等核心概念。Objective-C是基于Smalltalk的面向对象语言,它引入了“协议”(protocols)和“类别”(categories)等独特特性,...

    iPhone4开发入门 Beginning iPhone 4 +源代码.zip

    这本书由David Mark、Jeff LaMarche和Jack Nutting三位专家撰写,他们深入浅出地讲解了如何使用iOS SDK进行应用程序开发。书中不仅包含了理论知识,还有丰富的实践案例,旨在帮助读者快速掌握iOS编程技能。 首先,...

    iphone 开发Objective-C

    ### Objective-C基础教程:iPhone开发必备 ...对于希望从事iOS开发的专业人士来说,《Objective-C基础教程》是一本不可多得的好书,它不仅深入浅出地讲解了Objective-C的各种特性,还通过丰富的示例帮助读者快速上手。

    iPhone5与iPad开发必备基础教程【英文原版 PDF】

    《iPhone5与iPad开发必备基础教程》是一本专为初学者设计的iOS开发指南,英文原版PDF形式提供了深入浅出的讲解。本书的核心目标是帮助读者掌握在iPhone5和iPad上进行应用开发的基本技能,尤其针对iOS 5版本进行了...

    iphone基础编程2

    斯坦福大学的这门课程以其深入浅出的教学方式而闻名,即使是对于编程新手来说也十分友好。讲义以英文编写,但用词清晰,概念解释详尽,使得复杂的编程概念变得易于理解。这是一份宝贵的教育资源,它不仅涵盖了基本的...

    iphone基础编程讲义6

    《iPhone基础编程讲义6》是一份源自斯坦福大学的教育资源,主要针对初学者,以英文形式深入浅出地介绍了iOS应用开发的基础知识。这份讲义涵盖了iPhone编程的关键概念和技术,帮助开发者逐步掌握构建iPhone应用的技能...

    iPhone 斯坦福大学教学课件

    斯坦福大学的iPhone编程课程以其深入浅出的讲解闻名,即使对于英文不甚精通的学习者来说,也能轻松理解其中的知识点。本课程主要围绕Objective-C语言和iOS应用开发的核心概念展开,旨在帮助开发者掌握创建iPhone应用...

    Learn Objective-C on the mac

    《在Mac上学习Objective-C》是一本针对iPad和iPhone应用开发入门的经典教程,它深入浅出地介绍了Objective-C这门编程语言,以及如何利用它在苹果的生态系统中创建应用程序。Objective-C是苹果平台的主要开发语言,是...

    iOS_5_Programming_Cookbook.pdf

    这本书深入浅出地介绍了如何利用Objective-C语言和Xcode开发工具来构建功能丰富的iPhone和iPad应用程序。书中的内容丰富多样,涵盖了从基本的UI设计到复杂的网络编程的各种技巧和解决方案。 在iOS 5的开发环境中,...

    GNUstep API函数速查手册

    这本手册深入浅出地介绍了GNUstep中的各种API函数,对于熟悉iOS开发的程序员来说,它同样具有参考价值,因为Objective-C是iPhone和iPad应用开发的主要语言。 在Objective-C编程中,`NSStep`可能指的是`NSObject`的...

    一步一步iOS5编程第三版

    《一步一步iOS5编程 第三版》是一本专为iOS开发初学者设计的详细教程,它以iOS5为核心,深入浅出地介绍了iOS平台上的应用程序开发技术。这本书旨在帮助读者掌握苹果公司的移动操作系统上的编程技能,无论是对iOS设备...

    object-c基础教程

    本教程将深入浅出地介绍Object-C的基础知识,帮助初学者快速入门。 ### 一、Object-C简介 Object-C是在C语言基础上扩展的,增加了面向对象的特性,如类、继承、消息传递等。它的语法与Smalltalk非常相似,但同时也...

    Programming in object-c 2.0.pdf

    Kochan凭借丰富的经验和深入浅出的讲解方式,使本书成为学习Objective-C的首选教材。本书不仅覆盖了Objective-C的基础知识,还深入探讨了面向对象编程的核心概念,并通过实例展示了如何在实际项目中应用这些技术。 ...

    Programming in Objective-C(最新第四版)

    - **Objective-C简介**:本书为初学者提供了深入浅出的Objective-C介绍,无需预先掌握面向对象编程语言或C语言的基础。 - **编程入门**:通过实例介绍如何编写基本的Objective-C程序,包括变量、数据类型、运算符等...

Global site tag (gtag.js) - Google Analytics