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

【转载】IOS项目转移到自动计数

    博客分类:
  • IOS
 
阅读更多

这里主要参考了Apple官方文档:Transitioning to ARC Release Notes

在支持iOS5的Xcode4中,创建项目会看到这样的选项:

这是iOS5的新特性,自动对象引用计数。默认情况下是勾选的,当然你可以取消它,按照以前的方式手动释放对象内存。

自动引用计数(简称ARC)是一个编译时特性,用于Objective-C对象自动内存管理。你可能会联想到Java的自动垃圾回收(GC),但是如刚才提到的,它们有一个本质不同,ARC是一个编译时技术,你可以想像为,编译时将手动释放内存引用代码加入到你的代码中,并完成编译。从这点来看,实现原理类似Java的范型计数。

对于熟悉手动释放内存的开发者来说,设计开发庞大应用的时候,要验算每个使用过的对象是否被正确的释放了。有了ARC以后,开发者可更多的将注意力放在如何实现用户需求,而不是浪费在这样的系统需求上。不过,ARC是个新事物,学习它也需要成本,对于一些被项目压的喘不过气来的开发者,往往没有精力学习和评估怎样进行切换。希望我的文章能帮助他们。

上面这张图很形象的说明了手动释放内存和使用ARC特性的代码,可以看到ARC可让开发者编写更少的代码(不必写保持和释放对象的代码),因此花费的时间更少。

 

综述

再进一步说一下ARC的基本概念,它通过在编译时增加代码,让对象在不需要的时候释放,而不会存在更长时间。理论上,它和手动引用计数释放内存的效果时一样的,相当于为代码自动增加retain,release和autorelease方法的调用。

为了能在编译时生成正确的代码,ARC对代码中的方法有一些限制,后面会提到。另外,ARC引入了新的生命周期标识符,用于对象引用和属性的声明。

ARC在Xcode 4.2中得到支持,可支持Mac OSX 10.6和10.7,以及iOS4和iOS5。弱引用在Mac OSX 10.6和iOS4中不支持。

Xcode通过一个新的工具可自动将代码转换(比如删除retain和release调用)为ARC方式,并且帮助开发者借鉴不能自动转换的问题。该工具可转换项目中所有的文件,使之使用ARC,也可以选择转换指定的文件,让其他文件还使用手动引用计数。

 

ARC浏览

ARC替代了以前使用retain、release和autorelease的方式。ARC在编译时评估对象的生命周期并自动插入适当的方法调用。编译器也会生成适当的dealloc方法调用。总的来说,在使用ARC时,只有当使用方法名称约定的代码,是你需要使用手动引用计数的情况。

下面看示例,一个实现Person类的代码:

 

@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引入的新的生命周期修饰符。这里先不具体介绍它,后面再详细说明。

使用ARC,在contrived方法中创建Person实例的代码类似下面这样:

- (void)contrived {
    Person *aPerson = [[Person alloc] init];
    [aPerson setFirstName:@"William"];
    [aPerson setLastName:@"Dudney"];
    [aPerson:setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]];
    NSLog(@”aPerson: %@”, aPerson);
} 

因为ARC接管了内存管理,因此Person和NSNumber实例都不会内存泄漏。

可以很安全的为Person类实现下面的方法:

- (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,当然也不能使用比如@selector(retain)等形式。
    另外,如果你实现了dealloc方法,不可以用于释放实例变量,但是你可以在此对系统的对象执行setDelegate:nil操作,因为系统的类(或者其他代码)未使用ARC进行编译。
    ARC情况下自定义实现的dealloc方法 ,不可以调用[super dealloc],这会引起编译错误。
    当然,你还可以继续使用CFRetain、CFRelease和其他core fundation对象相关的函数,因为它们没有通过ARC编译。 
  • 不可以使用NSAllocateObject和NSDeallocateObject。
     你可以使用alloc创建对象,运行时会处理对象的dealloc。
  • 你不可以在C结构体中使用对象指针。
    作为替代,需要创建Objective-C类来管理数据。 
  • 不可以再随意的转换id和void *类型。
    //todo 
  • 不能再使用NSAutoreleasePool对象。
    ARC提供了@autoreleasepool块代替它。这比使用NSAutoreleasePool更有效。 
  • 不能再使用内存区。
    不再需要在任何情况下使用NSZone,它将被新的Objective-C运行时忽略。
  • ARC为了能和以前手动保持和释放内存的代码兼容,在方法和变量命名上做了限制,即不能让属性的名称前缀是new。

ARC引入的新的生命周期修饰符

这里要提前说两个概念,弱引用(weak reference)和归零弱引用(zeroing weak reference)。

这两个概念,本文参考了:Zeroing Weak References in Objective-C

什么是弱引用,看下面例子:

    – (void)setFoo: (id)newFoo
    {
        _foo = newFoo;
    }

这里_foo引用了newFoo,但是没有做retain,因此没有参与引用实例的生命周期。如果其他地方release造成该对象dealloc, _foo指向的对象将不可用。那会发生什么呢?我想很多程序员都碰到过这类情况,应用往往会崩溃(闪退)。

Cocoa框架中使用deletate引用的对象,几乎总是采用弱引用,就是利用了弱引用的这个特点。

什么是归零弱引用,刚才提到弱引用,一不小心,应用就崩溃了。归零弱引用在前者基础上,增加了保护措施,一旦引用对象被销毁,它会自动返回nil。这个特性在Mac OS X开发中已经使用:

__weak id _foo;

但是它需要GC支持,这个特性在iOS开发中不可用。

现在,iOS5推出的ARC特性,不但包含了对弱引用的支持,甚至可以替代GC特性在Mac OS X开发的作用。

有关属性值关键字,ARC引入了strong和weak关键字。

强引用:

@property(strong) MyClass *myObject; //你可以看作加了retain操作

弱引用:

@property(weak) MyClass *myObject; //和以前@property(assign) MyClass *myObj语法是类似的,但对象销毁自动返回nil

有关变量的标识符,如下:

  • __strong,默认值
  • __weak,标识对象是归零弱引用
  • __unsafe_unretained,标识对象是弱引用
  • __autoreleasing,标识对象在return时自动释放

在这里,__weak要小心使用,比如:

这样使用__weak,在后面的打印语句执行的时候将是null,因为弱引用不保持对象,这句话执行后对象就被释放了。

好在如上面截图所示,Xcode会给出警告作为提示。

另外,需要注意局部变量和方法参数修饰符的匹配。比如,有这样的方法:

-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;

然后这样使用该方法:

NSError *error = nil;

BOOL OK = [myObject performOperationWithError:&error];
if (!OK) {

这里的NSError *error = nil,会被自动编译为:

NSError * __strong e = nil;

那么,ARC为了匹配局部变量和方法参数,会产生中间临时变量:

NSError __strong *error = nil;
NSError __autoreleasing *tmp = error;
BOOL OK = [myObject performOperationWithError:&tmp];
error = tmp;
if (!OK) {

解决办法是,要么把局部变量设置为__autorelease,要么把方法参数设置为__strong。

 

使用生命周期修饰符,避免强引用循环

这里先说下,什么是强引用循环。比如A对象在属性中retain了B对象,而B对象在属性中也retain了A对象,那么它们之间存在了强引用循环。当然在实际开发中,可能这个循环更大,可能是多于2个对象产生了这种循环,变得更加难以察觉。

使用生命周期修饰符,可避免这种情况。比如,开发中常碰到的父子结构的对象关系。要求它们之间相关引用。那么可以让父对象强引用(__strong)子对象,子对象归零弱引用(__weak)父对象。

当然事情可能没那么简单,比如开发中使用了块对象。在手工引用计数模式下:

__block id x;

效果相当于没有保持x在内存中。

在ARC模式下,该语句,默认是保持的。如果还是想在ARC模式下实现手动引用的效果,则需要改为:

 __unsafe_unretained __block id x;

不过,这种弱引用,将造成危险(因为可能会造成危险),因此不建议使用。

那么怎么办呢?你有两种选择:

  1. 使用__weak标识符替代__block标识符,缺点是不支持iOS4和Mac OS X 10.6
  2. 不改变__block标识符,在块中使用完该变量后,设置变量为nil,这样就不会循环保持了

 

ARC提供了新的语句管理自动释放池

使用ARC后,就不能再直接使用NSAutoReleasePool类了。ARC引入了新的语法和语句:

@autoreleasepool {
     // Code, such as a loop that creates a large number of temporary objects.
}

编译器根据这个结构,检查语法块中对象引用计数的状态。

进入语法块的时候,自动释放池会压栈,正常退出时,比如运行到块外,则会弹栈。不过,为了兼容已存在代码,如果退出时有异常,则不弹栈。

这个语法可用于各种Objective-C模式。这比以前使用NSAutoReleasePool类更有效,建议替代使用。

 

管理Outlet的方式可以在Mac和iOS下一致了

这个方式就是:

  • outlet都应该是week的
  • 除了nib文件中文件所有者到顶级对象的那些顶级对象,它们应该用strong

 

局部变量都会被初始化为nil

使用ARC后,不论使用哪个修饰符,strong,weak还是其他的,都会被隐含的初始化为nil:

- (void)myMethod {
    NSString *name;
    NSLog(@”name: %@”, name);
}

无论是否变换修饰符,目前默认是strong,打印的结果都是nil。

 

使用编译器标志启用和禁用ARC

可通过新的标志-fobjc-arc启用ARC。还可以指定单个文件使用ARC。比如你可以指定项目使用ARC,然后再禁用某几个文件的这个标志。

ARC只在Xcode4.2被支持,4.1不支持ARC。ARC支持Mac OS X 10.6和10.7,也支持iOS4和iOS5。不过,Mac OS X 10.6和iOS4不支持弱引用。

 

在ARC模式下使用Core Function风格的类

比如,CFArrayRef,或者某些使用Core Function约定的框架,比如Core Graphic中的CGColorSpaceRef等。

编译器无法自动管理这些对象的生命周期。你必须调用比如CFRetain和CFRelease这样的方法管理它们。

如果你想在Objective-C和Core Foundation风格的对象间转型,需要告知编译器该对象的所有者。

有两种办法:

  1. 如果喜欢函数调用,可以使用类似CFBridgingRetain这样的宏
  2. 如果喜欢C风格的转型,可直接做转型

 

编译器对Cocoa方法返回的CF对象的处理

编译器可通过Core Foundation方式的命名规则理解这些,对Objective-C返回的CF对象做正确的处理。

 

使用所有者关键字转型函数的参数

如果要在函数调用中转型Objective-C和CF对象,你需要告诉编译器传递的对象的所有者关系。

CF对象和Objective-C对象都有自己定义的所有者关系规则,可见:

分享到:
评论

相关推荐

    ios5之自动引用计数

    ### iOS5之自动引用计数 #### 概述 在iOS5中,苹果引入了一项重大的内存管理改进——自动引用计数(Automatic Reference Counting,简称ARC)。这项技术简化了开发者对内存管理的需求,使得他们能够更加专注于应用...

    iOS自动化测试的演示项目

    "iOS自动化测试的演示项目"是一个专门为Xcode 4.2设计的实例,旨在教会开发者如何在该版本的Xcode中设置和执行自动化测试。下面将详细阐述iOS自动化测试的相关知识点,以及与"LoginWindow"相关的测试内容。 首先,...

    ios-ios代码自动化工具.zip

    要将这个自动化工具集成到自己的iOS项目中,开发者首先需要按照README.md的指示配置环境,然后将项目中的脚本和配置文件引入到自己的工程中。根据具体的自动化需求,可能需要修改或扩展脚本。 6. **版本控制与协作...

    iOS自动化测试自动允许弹框

    在iOS自动化测试中,经常会遇到应用在运行过程中弹出请求权限的对话框,例如访问相册、使用相机或获取地理位置信息。这些权限对话框如果不能正确处理,将导致自动化脚本无法正常执行。本篇文章将深入探讨如何使用...

    iOS项目通过GitLabe-runner自动打包配置

    该方法适用于使用Git进行版本控制的iOS项目,尤其是需要自动化打包并部署到不同环境(如开发、测试、生产)的情况。 三、环境配置 1. **Homebrew 安装** 在Mac上安装GitLab-runner前,首先需要确保已安装Homebrew...

    IOS手机录屏 IOS自动化

    而"iOS手机录屏"结合"iOS自动化"则将这一功能提升到了一个新的层次,使得批量、定时或者基于特定条件的录屏操作成为可能。在iOS自动化中,WebDriverAgent (WDA) 是一个关键的组件,它是Facebook开源的一个iOS自动化...

    swift-AutoPackage-iOS项目自动打包脚本

    Swift-AutoPackage-iOS项目自动打包脚本是一个用于简化iOS应用程序打包流程的工具,它能够自动化处理构建、签名和导出IPA等繁琐任务。在Swift开发中,特别是涉及到ARKit增强现实技术的项目,手动打包过程可能会变得...

    IOS项目37大案例.rar

    基于Xcode开发工具使用Swift语言开发的的IOS项目37大案例。Xcode 是运行在操作系统Mac OS X上的集成开发工具(IDE),Swift 是一种支持多编程范式和编译式的开源编程语言,苹果于2014年WWDC(苹果开发者大会)发布,...

    ios项目适配ios6 ios7

    本项目主要关注的是如何将一个iOS项目适配到iOS6和iOS7这两个版本,因为它们之间存在显著的视觉和用户体验差异。iOS7引入了全新的设计语言,这使得许多在iOS6中正常工作的元素在新系统中可能需要调整。下面我们将...

    iOS自动编译工具

    "iOS自动编译工具"是一种利用Python编写的脚本,旨在简化iOS应用的构建和发布流程,特别是将其上传到蒲公英(iHoe)这样的第三方分发平台。蒲公英是一个便捷的iOS应用测试和分享平台,开发者可以通过它快速地分享...

    iOS代码自动翻新(混淆)专家.zip

    .zip,u3d、cocos2dx、iOS代码混淆、自动翻新专家(WHC_ConfuseSoftware)是一款新一代运行在MAC OS平台的App、完美支持Objc和Swift、U3D、Cocos2dx项目代码的自动翻新(混淆)、支持文件夹名称、文件名、修改资源文件...

    《iOS开发项目化入门教程》源代码

    《iOS开发项目化入门教程》源代码是一份针对初学者的宝贵资源,旨在通过实际项目的实践,帮助开发者快速掌握iOS应用程序开发的基础技能。这个压缩包包含了一系列与iOS开发相关的源代码文件,这些文件反映了iOS应用从...

    使用python脚本轻松定制自动化iOS项目打包IPA并上传到appstore.zip

    使用python脚本轻松定制自动化iOS项目打包IPA并上传到appstore.zip 主要功能 打包项目(.xcodeproj, .xcworkspace), 生成.xcarchive 生成.ipa 导出.DSYM 上传ipa到appstore

    淘宝的IOS自动化方案

    淘宝的iOS自动化方案是针对iOS应用开发过程中,为了提高效率、减少手动操作、确保软件质量而设计的一套工具集和流程。这套方案旨在通过自动化测试、构建、部署等...对于大型的iOS项目,这样的自动化策略是非常必要的。

    iOS自动化脚本:用于构建iOS应用并部署到TestFlight或本地设备

    将YourProject.xcodeproj替换为你的Xcode项目文件路径。 将YourScheme替换为你的Xcode项目的Scheme名称。 创建一个ExportOptions.plist文件,并配置导出选项(例如,方法、团队ID等),然后指定其路径到EXPORT_...

    IOS项目实战

    在iOS开发领域,项目实战是提升技能和理解实际...通过这个项目,你不仅可以提升Swift编程能力,还能学习到iOS应用开发的全过程,包括设计、实现、测试和发布。这对于准备投身iOS开发领域的实践者来说是非常宝贵的经验。

    在存在iOS项目添加Cordova实现H5调用设备相册

    然后,添加iOS平台到你的项目中: ``` cordova platform add ios ``` 为了实现H5调用设备相册,我们需要引入Cordova的Camera插件。在命令行中运行以下命令来安装相机插件: ``` cordova plugin add cordova-plugin-...

    Jenkins项目实战之-xcode+jenkins自动化打iOS包.rar

    本篇将详细讲解如何使用Jenkins结合Xcode进行iOS应用的自动化打包流程,旨在帮助开发者实现高效的iOS项目构建和发布。 **一、Jenkins简介** Jenkins是一款开源的持续集成工具,广泛应用于自动化各种任务,如编译、...

Global site tag (gtag.js) - Google Analytics