`
miss大为
  • 浏览: 82726 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

IOS 5编程 内存管理 ARC技术概述

 
阅读更多
原文:http://blog.csdn.net/nicktang/article/details/6792972

Automatic Reference Counting (ARC) 是一个编译期的技术,利用此技术可以简化Objective-C编程在内存管理方面的工作量。
这里我把此技术翻译为自动内存计数器管理技术,下图是使用和不使用此技术的Objective-C代码的区别。

ARC技术是随着XCode4.2一起发布的,在缺省工程模板中,你可以指定你的工程是否支持ARC技术,如果你不指定工程支持ARC技术,在代码中你必须使用管理内存的代码来管理内存。

概述
自动计数(ARC)是一个编译期间工作的能够帮你管理内存的技术,通过它,程序人员可以不需要在内存的retain,释放等方面花费精力。
ARC在编译期间为每个Objective-C指针变量添加合适的retain, release, autorelease等函数,保存每个变量的生存周期控制在合理的范围内,以期实现代码上的自动内存管理。
In order for the compiler to generate correct code, ARC imposes some restrictions on the methods you can use, and on how you use toll-free bridging (see “Toll-Free Bridged Types”); ARC also introduces new lifetime qualifiers for object references and declared properties.
你可以使用编译标记-fobjc-arc来让你的工程支持ARC。ARC在Xcode4.2中引入,在Mac OS X v10.6,v10.7 (64位应用),iOS 4,iOS 5中支持,Xcode4.1中不支持这个技术.
如果你现在的工程不支持ARC技术,你可以通过一个自动转换工具来转换你的工程(工具在Edit->Convert menu),这个工具会自动所有工程中手动管理内存的点转换成合适自动方式的(比如移除retain, release等)。这个工具会转换工程中所有的文件。当然你可以转换单个文件。
ARC提供自动内存管理的功能
ARC使得你不需要再思考何时使用retain,release,autorelease这样的函数来管理内存,它提供了自动评估内存生存期的功能,并且在编译期间自动加入合适的管理内存的方法。编译器也会自动生成dealloc函数。一般情况下,通过ARC技术,你可以不顾传统方式的内存管理方式,但是深入了解传统的内存管理是十分有必要的。
下面是一个person类的一个声明和实现,它使用了ARC技术。
@interface Person : NSObject
@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, strong) NSNumber *yearOfBirth;
@property (nonatomic, strong) Person *spouse;
@end
 
@implementation Person
@synthesize firstName, lastName, yearOfBirth, spouse;
@end

(有关strong的帮助,请参考 “ARC Introduces New Lifetime Qualifiers.”)
使用ARC,你可以象下面的方式实现contrived函数:
- (void)contrived {
    Person *aPerson = [[Person alloc] init];
    [aPerson setFirstName:@"William"];
    [aPerson setLastName:@"Dudney"];
    [aPerson:setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]];
    NSLog(@"aPerson: %@", aPerson);
}

ARC管理内存,所以这里你不用担心aPerson和NSNumber的临时变量会造成内存泄漏。
你还可以象下面的方式来实现Person类中的takeLastNameFrom:方法,
- (void)takeLastNameFrom:(Person *)person {
    NSString *oldLastname = [self lastName];
    [self setLastName:[person lastName]];
    NSLog(@"Lastname changed from %@ to %@", oldLastname, [self lastName]);
}

ARC可以保证在NSLog调用的时候,oldLastname还存在于内存中。
ARC中的新规则
为了ARC能顺利工作,特增加如下规则,这些规则可能是为了更健壮的内存管理,也有可能为了更好的使用体验,也有可能是简化代码的编写,不论如何,请不要违反下面的规则,如果违反,将会得到一个编译期错误。
下面的这些函数:dealloc,retain, release, retainCount, autorelease。禁止任何形式调用和实现(dealloc可能会被实现),包括使用@selector(retain), @selector(release)等的隐含调用。
你可能会实现一个和内存管理没有关系的dealloc,譬如只是为了调用[systemClassInstance setDelegate:nil] ,但是请不要调用[super dealloc] ,因为编译器会自动处理这些事情。
你不可以使用NSAllocateObject或者NSDeallocateObject.
使用alloc申请一块内存后,其他的都可以交给运行期的自动管理了。
不能在C语言中的结构中使用Objective-c中的类的指针。
请使用类类管理数据。
不能使用NSAutoreleasePool.
作为替代,@autoreleasepool被引入,你可以使用这个效率更高的关键词。
不能使用memory zones.
NSZone不再需要—本来这个类已经被现代Objective-c废弃。
ARC在函数和便利变量命名上也有一些新的规定
禁止以new开头的属性变量命名。
ARC Introduces New Lifetime Qualifiers
ARC introduces several new lifetime qualifiers for objects, and zeroing weak references. A weak reference does not extend the lifetime of the object it points to. A zeroing weak reference automatically becomes nil if the object it points to is deallocated.
You should take advantage of these qualifiers to manage the object graphs in your program. In particular, ARC does not guard against strong reference cycles (previously known as retain cycles—see “Practical Memory Management”). Judicious use of weak relationships will help to ensure you don’t create cycles.
属性变量修饰符

weak和strong两个修饰符是新引进的,使用例子如下:
// 下面的作用和: @property(retain) MyClass *myObject;相同
@property(strong) MyClass *myObject;
 
// 下面的作用和"@property(assign) MyClass *myObject;"相识
// 不同的地方在于,如果MyClass的实例析构后,这个属性变量的值变成nil,而不是一个野指针,
 
@property(weak) MyClass *myObject;

Variable Qualifiers

You use the following lifetime qualifiers for variables just like you would, say, const.
__strong
__weak
__unsafe_unretained
__autoreleasing

__strong is the default. __weak specifies a zeroing weak reference to an object. __unsafe_unretained specifies weak reference to an object that is not zeroing—if the object it references is deallocated, the pointer is left dangling. You use__autoreleasing to denote arguments that are passed by reference (id *) and are autoreleased on return.
Take care when using __weak variables on the stack. Consider the following example:
NSString __weak *string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
NSLog(@"string: %@", string);

Although string is used after the initial assignment, there is no other strong reference to the string object at the time of assignment; it is therefore immediately deallocated. The log statement shows that string has a null value.
You also need to take care with objects passed by reference. The following code will work:
NSError *error = nil;
BOOL OK = [myObject performOperationWithError:&error];
if (!OK) {
    // Report the error.
    // ...

However, the error declaration is implicitly:
NSError * __strong e = nil;
and the method declaration would typically be:
-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;
The compiler therefore rewrites the code:
NSError __strong *error = nil;
NSError __autoreleasing *tmp = error;
BOOL OK = [myObject performOperationWithError:&tmp];
error = tmp;
if (!OK) {
    // Report the error.
    // ...

The mismatch between the local variable declaration (__strong) and the parameter (__autoreleasing) causes the compiler to create the temporary variable. You can get the original pointer by declaring the parameter id __strong * when you take the address of a __strong variable. Alternatively you can declare the variable as __autoreleasing.
Use Lifetime Qualifiers to Avoid Strong Reference Cycles

You can use lifetime qualifiers to avoid strong reference cycles. For example, typically if you have a graph of objects arranged in a parent-child hierarchy and parents need to refer to their children and vice versa, then you make the parent-to-child relationship strong and the child-to-parent relationship weak. Other situations may be more subtle, particularly when they involve block objects.
In manual reference counting mode, __block id x; has the effect of not retaining x. In ARC mode, __block id x; defaults to retaining x (just like all other values). To get the manual reference counting mode behavior under ARC, you could use__unsafe_unretained __block id x;. As the name __unsafe_unretained implies, however, having a non-retained variable is dangerous (because it can dangle) and is therefore discouraged. Two better options are to either use __weak (if you don’t need to support iOS 4 or OS X v10.6), or set the __block value to nil to break the retain cycle.
The following code fragment illustrates this issue using a pattern that is sometimes used in manual reference counting.
MyViewController *myController = [[MyViewController alloc] init…];
// ...
myController.completionHandler =  ^(NSInteger result) {
   [myController dismissViewControllerAnimated:YES completion:nil];
};
[self presentViewController:myController animated:YES completion:^{
   [myController release];
}];

As described, instead, you can use a __block qualifier and set the myController variable to nil in the completion handler:
__block MyViewController *myController = [[MyViewController alloc] init…];
// ...
myController.completionHandler =  ^(NSInteger result) {
    [myController dismissViewControllerAnimated:YES completion:nil];
    myController = nil;
};

Alternatively, you can use a temporary __weak variable. The following example illustrates a simple implementation:
MyViewController *myController = [[MyViewController alloc] init…];
// ...
__weak MyViewController *weakMyViewController = myController;
myController.completionHandler =  ^(NSInteger result) {
    [weakMyViewController dismissViewControllerAnimated:YES completion:nil];
};

For non-trivial cycles, however, you should use:
MyViewController *myController = [[MyViewController alloc] init…];
// ...
__weak MyViewController *weakMyController = myController;
myController.completionHandler =  ^(NSInteger result) {
    MyViewController *strongMyController = weakMyController;
    if (strongMyController) {
        // ...
        [strongMyController dismissViewControllerAnimated:YES completion:nil];
        // ...
    }
    else {
        // Probably nothing...
    }
};

In some cases you can use __unsafe_unretained if the class isn’t __weak compatible. This can, however, become impractical for nontrivial cycles because it can be hard or impossible to validate that the __unsafe_unretained pointer is still valid and still points to the same object in question.
自动释放池
使用ARC,你不能使用NSAutoReleasePool类来管理自动释放池了,作为替代,ARC使用一个新的语法结构:
@autoreleasepool {
     // Code, such as a loop that creates a large number of temporary objects.
}

编译器根据工程是否使用ARC,来决定这个语法结构最终呈现方式,这个语法结构使用了一种比NSAutoReleasePool更高效的方式。
Outlets
The patterns for declaring outlets in iOS and OS X change with ARC and become consistent across both platforms. The pattern you should typically adopt is: outlets should be weak, except for those from File’s Owner to top-level objects in a nib file (or a storyboard scene) which should be strong.
Outlets that you create should will therefore generally be weak by default:
Outlets that you create to, for example, subviews of a view controller’s view or a window controller’s window, are arbitrary references between objects that do not imply ownership.
The strong outlets are frequently specified by framework classes (for example, UIViewController’s view outlet, or NSWindowController’s window outlet).
For example:
@interface MyFilesOwnerClass : SuperClass
 
@property (weak) IBOutlet MyView *viewContainerSubview;
@property (strong) IBOutlet MyOtherClass *topLevelObject;
@end

In cases where you cannot create a weak reference to an instance of a particular class (such as NSTextView), you should use assign rather than weak:
@property (assign) IBOutlet NSTextView *textView;

This pattern extends to references from a container view to its subviews where you have to consider the internal consistency of your object graph. For example, in the case of a table view cell, outlets to specific subviews should again typically beweak. If a table view contains an image view and a text view, then these remain valid so long as they are subviews of the table view cell itself.
Outlets should be changed to strong when the outlet should be considered to own the referenced object:
As indicated previously, this often the case with File’s Owner: top level objects in a nib file are frequently considered to be owned by the File’s Owner.
You may in some situations need an object from a nib file to exist outside of its original container. For example, you might have an outlet for a view that can be temporarily removed from its initial view hierarchy and must therefore be maintained independently.
其他的新功能
使用ARC技术,可以使得在栈上分配的指针隐式的初始化为nil,比如
- (void)myMethod {
    NSString *name;
    NSLog(@"name: %@", name);
}

上面的代码会Log出来一个null,不会象不使用ARC技术的时候使得程序崩溃。
分享到:
评论

相关推荐

    IOS高级内存管理编程指南.pdf

    iOS高级内存管理编程指南主要介绍了iOS环境下对象的内存管理机制,尤其在Objective-C编程语言中的内存管理方式。在iOS应用开发中,内存管理对于保证应用的稳定运行至关重要。本文将详细介绍iOS内存管理的知识点,...

    ios高级内存管理编程指南

    ### iOS高级内存管理编程指南 #### 一、内存管理概览与重要性 在iOS开发过程中,内存管理是一项至关重要的技能。不当的内存管理不仅会导致应用程序崩溃,还可能引起性能问题,甚至导致用户数据丢失。因此,深入...

    cocos 2d 游戏编程指南(兼容iOS 5 ARC)

    本书是一本针对cocos2d游戏开发的全面指南,适用于iOS 5环境下的ARC(Automatic Reference Counting)自动内存管理机制。本书旨在帮助读者深入理解cocos2d框架及其在iOS平台上的应用,并通过实际案例教授读者如何构建...

    iOS编程 第四版 高清中文版

    ### iOS编程第四版知识点概述 #### 一、书籍基本信息 - **书名**:《iOS编程...通过以上概述可以看出,《iOS编程 第四版》是一本全面覆盖iOS开发技术的书籍,不仅适合初学者入门,也适合有一定基础的开发者进阶学习。

    内存管理编程指南

    在进行编程尤其是使用Objective-C语言开发应用程序时,内存管理是一项核心技能,它确保了程序能够高效地使用系统资源。内存管理指的是控制程序中的数据存储和访问,以及如何在不需要数据时释放它所占用的内存空间。...

    iOS5开发基础教程

    10. **ARC(Automatic Reference Counting)**:iOS 5引入的内存管理机制,自动处理对象的引用计数。书中会讲解如何使用ARC避免内存泄漏。 11. **Storyboards**:一种可视化方式,用于构建应用程序的导航流程。...

    iOS 5 by Tutorials

    通过以上章节内容的详细介绍,我们可以看出《iOS 5 by Tutorials》不仅覆盖了iOS 5的核心技术和新特性,还提供了大量的实践案例和代码示例,对于希望深入学习iOS开发的读者来说是一本非常有价值的教程书籍。

    IOS和Cocos2D编程总结

    - **内存管理**:iOS采用自动引用计数(ARC)进行内存管理,理解引用计数和循环引用是避免内存泄漏的关键。 - **多线程**:GCD(Grand Central Dispatch)是iOS中处理并发任务的重要工具,学习如何使用队列来实现...

    Pro Multithreading and Memory Management for iOS

    在iOS开发过程中,内存管理和多线程技术是确保应用性能与稳定性的重要环节。《Pro Multithreading and Memory Management for iOS》一书深入探讨了自动引用计数(ARC)、Grand Central Dispatch (GCD) 和 Blocks 的...

    ios5 By Tutorials

    - **ARC的概念**:解释了ARC的工作原理以及如何利用它简化内存管理。 - **ARC基本用法**:演示了如何在代码中使用ARC来自动管理对象的生命周期。 - **常见陷阱**:讨论了使用ARC时可能遇到的问题,并提供了解决方案...

    IOS视频教程地址 关东升老师主讲

    由于移动设备资源有限,iOS开发特别注重内存管理。教程会涉及Objective-C的自动引用计数(ARC)机制,帮助开发者理解何时创建和释放对象。 **模拟器与真机调试** 在开发过程中,使用iOS模拟器和真机进行调试是非常...

    Sams Teach Yourself iOS 5 Application Development in 24 Hours.

    - 内存管理:避免内存泄漏,合理使用ARC(自动引用计数)。 - 调试策略:设置断点、查看日志等技巧。 #### 五、总结 《Sams Teach Yourself iOS 5 Application Development in 24 Hours》是一本非常适合iOS开发...

    iOS_5_by_Tutorials_Second_Edition_1_1

    ARC简化了内存管理的过程,使得开发者无需手动管理内存分配和释放,从而降低了内存泄漏的风险。本章可能会讲解ARC的工作原理、常见陷阱以及如何有效利用ARC来提高代码的质量。 ### 第三章:中级ARC 在初级基础上,...

    IOS开发(第三期)

    - 内存管理:理解和掌握ARC(自动引用计数)机制,避免内存泄漏和过早释放等问题。 - 多线程:学习GCD(Grand Central Dispatch)和NSOperation等多线程编程技术,提高应用的响应性和效率。 - 动画效果:使用Core...

    IOS7 Programming Fundamentals

    5. **内存管理**:讲解了如何有效地管理对象的生命周期,包括引用计数和自动引用计数(Automatic Reference Counting, ARC)等技术。 6. **属性和合成**:探讨了如何声明属性以及如何实现属性的存取器方法。 7. **...

    iOS 4 Programming Cookbook

    11. **1.9 Managing Memory with the iOS SDK(使用iOS SDK管理内存)** - **知识点**: - 内存管理的原则; - ARC(Automatic Reference Counting)的工作原理; - 手动内存管理的最佳实践。 - **重要性**:...

    整集iOS面试资料

    - 对象的初始化和释放,以及内存管理机制ARC。 - 协议的使用,包括协议的声明、遵守协议的方法实现等。 **4. KVO-KVC** - KVO的概念及其使用场景。 - KVC的基本用法,包括属性的读取和设置。 - KVO和KVC的优缺点...

Global site tag (gtag.js) - Google Analytics