如何解除苹果设备锁怎么解除ID锁 Arc

深入理解Objective C的ARC机制
招聘信息:
前言本文的ARC特指Objective C的ARC,并不会讲解其他语言。另外,本文涉及到的原理部分较多,适合有一定经验的开发者。什么是ARC?ARC的全称Auto Reference Counting. 也就是自动引用计数。那么,为什么要有ARC呢?我们从C语言开始。使用C语言编程的时候,如果要在堆上分配一块内存,代码如下//分配内存(malloc/calloc均可)
int&*&array&=&calloc(10,&sizeof&(int));
//释放内存
free(array);C是面向过程的语言(Procedural programming),这种内存的管理方式简单直接。但是,对于面向对象编程,这种手动的分配释放毫无疑问会大大的增加代码的复杂度。于是,OOP的语言引入了各种各样的内存管理方法,比如Java的垃圾回收和Objective C的引用计数。关于垃圾回收和饮用计数的对比,可以参见Brad Larson的这个SO回答。Objective C的引用计数理解起来很容易,当一个对象被持有的时候计数加一,不再被持有的时候引用计数减一,当引用计数为零的时候,说明这个对象已经无用了,则将其释放。引用计数分为两种:手动引用计数(MRC)自动引用计数(ARC)在iOS开发早期,编写代码是采用MRC的//&MRC代码
NSObject&*&obj&=&[[NSObject&alloc]&init];&//引用计数为1
//不需要的时候
[obj&release]&//引用计数减1
//持有这个对象
[obj&retain]&//引用计数加1
//放到AutoReleasePool
[obj&autorelease]//在auto&release&pool释放的时候,引用计数减1虽说这种方式提供了面向对象的内存管理接口,但是开发者不得不花大量的时间在内存管理上,并且容易出现内存泄漏或者release一个已被释放的对象,导致crash。再后来,Apple对iOS/Mac OS开发引入了ARC。使用ARC,开发者不再需要手动的retain/release/autorelease. 编译器会自动插入对应的代码,再结合Objective C的runtime,实现自动引用计数。比如如下ARC代码:NSObject&*&
&&&&obj&=&[[NSObject&alloc]&init];&//引用计数为1
NSLog(@"%@",obj);等同于如下MRC代码NSObject&*&
&&&&obj&=&[[NSObject&alloc]&init];&//引用计数为1
&&&&[obj&relrease]
NSLog(@"%@",obj);在Objective C中,有三种类型是ARC适用的:blockobjective 对象,id, Class, NSError*等由attribute((NSObject))标记的类型。像double *,CFStringRef等不是ARC适用的,仍然需要手动管理内存。Tips: 以CF开头的(Core Foundation)的对象往往需要手动管理内存。属性所有权最后,我们在看看ARC中常见的所有权关键字,assign对应关键字__unsafe_unretained, 顾名思义,就是指向的对象被释放的时候,仍然指向之前的地址,容易引起野指针。copy对应关键字__strong,只不过在赋值的时候,调用copy方法。retain对应__strongstrong对应__strongunsafe_unretained对应__unsafe_unretainedweak对应__weak。其中,__weak和__strong是本文要讲解的核心内容。ARC的内部实现ARC背后的引用计数主要依赖于这三个方法:retain&增加引用计数release&降低引用计数,引用计数为0的时候,释放对象。autorelease&在当前的auto release pool结束后,降低引用计数。在Cocoa Touch中,NSObject协议中定义了这三个方法,由于Cocoa Touch中,绝大部分类都继承自NSObject(NSObject类本身实现了NSObject协议),所以可以“免费”获得NSObject提供的运行时和ARC管理方法,这就是为什么适用OC开发iOS的时候,你的类要继承自NSObject。既然ARC是引用计数,那么对应一个对象,内存中必然会有一个地方来存储这个对象的引用计数。iOS的Runtime是开源的,在这里可以下载到全部的代码,我们通过源代码一探究竟。我们从retain入手,-&(id)retain&{
&&&&return&((id)self)->rootRetain();
inline&id&objc_object::rootRetain()
&&&&if&(isTaggedPointer())&return&(id)
&&&&return&sidetable_retain();
}所以说,本质上retain就是调用sidetable_retain,再看看sitetable_retain的实现:id&objc_object::sidetable_retain()
&&&&//获取table
&&&&SideTable&&table&=&SideTables()[this];
&&&&//加锁
&&&&table.lock();
&&&&//获取引用计数
&&&&size_t&&refcntStorage&=&table.refcnts[this];
&&&&if&(!&(refcntStorage&&&SIDE_TABLE_RC_PINNED))&{
&&&&&&&&&//增加引用计数
&&&&&&&&refcntStorage&+=&SIDE_TABLE_RC_ONE;
&&&&//解锁
&&&&table.unlock();
&&&&return&(id)
}到这里,retain如何实现就很清楚了,通过SideTable这个数据结构来存储引用计数。我们看看这个数据结构的实现:可以看到,这个数据结构就是存储了一个自旋锁,一个引用计数map。这个引用计数的map以对象的地址作为key,引用计数作为value。到这里,引用计数的底层实现我们就很清楚了。存在全局的map,这个map以地址作为key,引用计数的值作为value。再来看看release的实现:&&&&SideTable&&table&=&SideTables()[this];
&&&&bool&do_dealloc&=&
&&&&table.lock();
&&&&//找到对应地址的
&&&&RefcountMap::iterator&it&=&table.refcnts.find(this);
&&&&if&(it&==&table.refcnts.end())&{&//找不到的话,执行dellloc
&&&&&&&&do_dealloc&=&
&&&&&&&&table.refcnts[this]&=&SIDE_TABLE_DEALLOCATING;
&&&&}&else&if&(it->second&second&|=&SIDE_TABLE_DEALLOCATING;
&&&&}&else&if&(!&(it->second&&&SIDE_TABLE_RC_PINNED))&{
&&&&//引用计数减去1
&&&&&&&&it->second&-=&SIDE_TABLE_RC_ONE;
&&&&table.unlock();
&&&&if&(do_dealloc&&&&&&performDealloc)&{
&&&&&&&&//执行dealloc
&&&&&&&&((void(*)(objc_object&*,&SEL))objc_msgSend)(this,&SEL_dealloc);
&&&&return&do_release的到这里也比较清楚了:查找map,对引用计数减1,如果引用计数小于阈值,则调用SEL_deallocAutorelease pool上文提到了,autorelease方法的作用是把对象放到autorelease pool中,到pool drain的时候,会释放池中的对象。举个例子&&&&__weak&NSObject&*&
&&&&NSObject&*&temp&=&[[NSObject&alloc]&init];
&&&&obj&=&
&&&&NSLog(@"%@",obj);&//非空放到auto release pool中,&&&&__weak&NSObject&*&
&&&&@autoreleasepool&{
&&&&&&&&NSObject&*&temp&=&[[NSObject&alloc]&init];
&&&&&&&&obj&=&
&&&&NSLog(@"%@",obj);&//null可以看到,放到自动释放池的对象是在超出自动释放池作用域后立即释放的。事实上在iOS 程序启动之后,主线程会启动一个Runloop,这个Runloop在每一次循环是被自动释放池包裹的,在合适的时候对池子进行清空。对于Cocoa框架来说,提供了两种方式来把对象显式的放入AutoReleasePool.NSAutoreleasePool(只能在MRC下使用)@autoreleasepool {}代码块(ARC和MRC下均可以使用)那么AutoRelease pool又是如何实现的呢?我们先从autorelease方法源码入手//autorelease方法
-&(id)autorelease&{
&&&&return&((id)self)->rootAutorelease();
//rootAutorelease&方法
inline&id&objc_object::rootAutorelease()
&&&&if&(isTaggedPointer())&return&(id)
&&&&//检查是否可以优化
&&&&if&(prepareOptimizedReturn(ReturnAtPlus1))&return&(id)
&&&&//放到auto&release&pool中。
&&&&return&rootAutorelease2();
//&rootAutorelease2
id&objc_object::rootAutorelease2()
&&&&assert(!isTaggedPointer());
&&&&return&AutoreleasePoolPage::autorelease((id)this);
}可以看到,把一个对象放到auto release pool中,是调用了AutoreleasePoolPage::autorelease这个方法。我们继续查看对应的实现:public:&static&inline&id&autorelease(id&obj)
&&&&&&&&assert(obj);
&&&&&&&&assert(!obj->isTaggedPointer());
&&&&&&&&id&*dest&__unused&=&autoreleaseFast(obj);
&&&&&&&&assert(!dest&&||&&dest&==&EMPTY_POOL_PLACEHOLDER&&||&&*dest&==&obj);
&&&&&&&&return&
static&inline&id&*autoreleaseFast(id&obj)
&&&&&&&&AutoreleasePoolPage&*page&=&hotPage();
&&&&&&&&if&(page&&&&!page->full())&{
&&&&&&&&&&&&return&page->add(obj);
&&&&&&&&}&else&if&(page)&{
&&&&&&&&&&&&return&autoreleaseFullPage(obj,&page);
&&&&&&&&}&else&{
&&&&&&&&&&&&return&autoreleaseNoPage(obj);
id&*add(id&obj)
&&&&&&&&assert(!full());
&&&&&&&&unprotect();
&&&&&&&&id&*ret&=&&&//&faster&than&`return&next-1`&because&of&aliasing
&&&&&&&&*next++&=&
&&&&&&&&protect();
&&&&&&&&return&
&&&&}到这里,autorelease方法的实现就比较清楚了,autorelease方法会把对象存储到AutoreleasePoolPage的链表里。等到auto release pool被释放的时候,把链表内存储的对象删除。所以,AutoreleasePoolPage就是自动释放池的内部实现。__weak与__strong用过block的同学一定写过类似的代码:__weak&typeSelf(self)&weakSelf&=&
[object&fetchSomeFromRemote:^{
&&&&__strong&typeSelf(weakSelf)&strongSelf&=&weakS
&&&&//从这里开始用strongSelf
}];那么,为什么要这么用呢?原因是:block会捕获外部变量,用weakSelf保证self不会被block被捕获,防止引起循环引用或者不必要的额外生命周期。用strongSelf则保证在block的执行过程中,对象不会被释放掉。首先__strong和__weak都是关键字,是给编译器理解的。为了理解其原理,我们需要查看它们编译后的代码,使用XCode,我们可以容易的获得一个文件的汇编代码。比如,对于Test.m文件,当源代码如下时:&#import&"Test.h"
&@implementation&Test
-&(void)testFunction{
&&&&&&&&__strong&NSObject&*&temp&=&[[NSObject&alloc]&init];
@end转换后的汇编代码如下:Ltmp3:
&&&&.loc&&&&2&15&37&prologue_end&&&&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:15:37
&&&&ldr&&&&&x9,&[x9]
&&&&ldr&&&&&x1,&[x8]
&&&&mov&&x0,&x9
&&&&bl&&_objc_msgSend
&&&&adrp&&&&x8,&L_OBJC_SELECTOR_REFERENCES_.2@PAGE
&&&&add&x8,&x8,&L_OBJC_SELECTOR_REFERENCES_.2@PAGEOFF
&&&&.loc&&&&2&15&36&is_stmt&0&&&&&&&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:15:36
&&&&ldr&&&&&x1,&[x8]
&&&&.loc&&&&2&15&36&discriminator&1&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:15:36
&&&&bl&&_objc_msgSend
&&&&mov&x8,&#0
&&&&add&x9,&sp,&#8&&&&&&&&&&&&&&;&=8
&&&&.loc&&&&2&15&29&&&&&&&&&&&&&&&&&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:15:29
&&&&str&x0,&[sp,&#8]
&&&&.loc&&&&2&16&5&is_stmt&1&&&&&&&&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:16:5
&&&&mov&&x0,&x9
&&&&mov&&x1,&x8
&&&&bl&&_objc_storeStrong
&&&&.loc&&&&2&17&1&&&&&&&&&&&&&&&&&&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:17:1
&&&&ldp&x29,&x30,&[sp,&#32]&&&&&;&8-byte&Folded&Reload
&&&&add&sp,&sp,&#48&&&&&&&&&&&&&;&=48
Ltmp5:即使你不懂汇编,也能很轻易的获取到调用顺序如下_objc_msgSend&//&alloc
_objc_msgSend&//&init
_objc_storeStrong&//&强引用在结合Runtime的源码,我们看看最关键的objc_storeStrong的实现void&objc_storeStrong(id&*location,&id&obj)
&&&&id&prev&=&*
&&&&if&(obj&==&prev)&{
&&&&objc_retain(obj);
&&&&*location&=&
&&&&objc_release(prev);
id&objc_retain(id&obj)&{&return&[obj&retain];&}
void&objc_release(id&obj)&{&[obj&release];&}我们再来看看__weak. 将Test.m修改成为如下代码,同样我们分析其汇编实现&&&&.loc&&&&2&15&35&prologue_end&&&&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:15:35
&&&&ldr&&&&&x9,&[x9]
&&&&ldr&&&&&x1,&[x8]
&&&&mov&&x0,&x9
&&&&bl&&_objc_msgSend
&&&&adrp&&&&x8,&L_OBJC_SELECTOR_REFERENCES_.2@PAGE
&&&&add&x8,&x8,&L_OBJC_SELECTOR_REFERENCES_.2@PAGEOFF
&&&&.loc&&&&2&15&34&is_stmt&0&&&&&&&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:15:34
&&&&ldr&&&&&x1,&[x8]
&&&&.loc&&&&2&15&34&discriminator&1&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:15:34
&&&&bl&&_objc_msgSend
&&&&add&x8,&sp,&#24&&&&&&&&&&&&&;&=24
&&&&.loc&&&&2&15&27&&&&&&&&&&&&&&&&&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:15:27
&&&&mov&&x1,&x0
&&&&.loc&&&&2&15&27&discriminator&2&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:15:27
&&&&str&x0,&[sp,&#16]&&&&&&&&&&&;&8-byte&Folded&Spill
&&&&mov&&x0,&x8
&&&&bl&&_objc_initWeak
&&&&.loc&&&&2&15&27&&&&&&&&&&&&&&&&&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:15:27
&&&&ldr&x1,&[sp,&#16]&&&&&&&&&&&;&8-byte&Folded&Reload
&&&&.loc&&&&2&15&27&discriminator&3&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:15:27
&&&&str&x0,&[sp,&#8]&&&&&&&&&&&&;&8-byte&Folded&Spill
&&&&mov&&x0,&x1
&&&&bl&&_objc_release
&&&&add&x8,&sp,&#24&&
&&&&Ltmp4:
&&&&.loc&&&&2&16&5&is_stmt&1&&&&&&&&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:16:5
&&&&mov&&x0,&x8
&&&&bl&&_objc_destroyWeak
&&&&.loc&&&&2&17&1&&&&&&&&&&&&&&&&&&;&/Users/hl/Desktop/OCTest/OCTest/Test.m:17:1
&&&&ldp&x29,&x30,&[sp,&#48]&&&&&;&8-byte&Folded&Reload
&&&&add&sp,&sp,&#64&&&&&&&&&&&&&;&=64
&&&&ret可以看到,__weak本身实现的核心就是以下两个方法_objc_initWeak_objc_destroyWeak我们通过Runtime的源码分析这两个方法的实现:id&objc_initWeak(id&*location,&id&newObj)
&&&&//省略....
&&&&return&storeWeak&&&&&&&&(location,&(objc_object*)newObj);
void&objc_destroyWeak(id&*location)
&&&&(void)storeWeak&&&&&&&&(location,&nil);
}所以,本质上都是调用了storeWeak函数,这个函数内容较多,主要做了以下事情获取存储weak对象的map,这个map的key是对象的地址,value是weak引用的地址。当对象被释放的时候,根据对象的地址可以找到对应的weak引用的地址,将其置为nil即可。这就是在weak背后的黑魔法。总结这篇文章属于想到哪里写到哪里的类型,后边有时间了在继续总结ARC的东西吧。
微信扫一扫
订阅每日移动开发及APP推广热点资讯公众号:CocoaChina
您还没有登录!请或
点击量6646点击量5944点击量4816点击量4543点击量3285点击量3068点击量2796点击量2552点击量2519
&2016 Chukong Technologies,Inc.
京公网安备89iPhone ARC机制
我的图书馆
iPhone ARC机制
ARC工作原理是在编译程序的时候由xCode将内存操作的代码(如:retain,release 和 autorelease)自动添加到需要的位置。ARC 只能在iOS4 和iOS5上使用,weak refrences 只能在iOS5上使用,并且只能是工程在ARC管理内存的时候才能用。老版本的工程是可以转换成使用ARC的工程,转换规则包括:&&&&&&&&1.去掉所有的retain,release,autorelease&&&&&&&&2.把NSAutoRelease替换成@autoreleasepool{}块&&&&&&&&3.把assign的属性变为weak使用ARC的一些强制规定&&&&&&&&1.不能直接调用dealloc方法,不能调用retain,release,autorelease,reraubCount方法,包括@selector(retain)的方式也不行&&&&&&&&2.截图租户事故宣布dealloc方法来管理一些资源,但不能用来释放实例变量,也不能在dealloc方法里面去掉[super dealloc]方法,在ARC下父类的dealloc同样由编译器来自动完成&&&&&&&&3.Core Foundation类型的对象任然可以用CFRetain,CFRelease这些方法&&&&&&&&4.不能在使用NSAllocateObject和NSDeallocateObject对象&&&&&&&&5.不能在c结构体中使用对象指针,如果有类似功能可以创建一个Objective-c类来管理这些对象&&&&&&&&6.在id和void *之间没有简便的转换方法,同样在Objective-c和core Foundation类型之间的转换都需要使用编译器制定的转换函数&&&&&&&&7.不能再使用NSAutoreleasePool对象,ARC提供了@autoreleasepool块来代替它,这样更加有效率&&&&&&&&8.不能使用内存存储区(不能再使用NSZone)&&&&&&&&9.不能以new为开头给一个属性命名&&&&&&&&10.声明outlet时一般应当使用weak,除了对StoryBoard 这样nib中间的顶层对象要用strong&&&&&&&&11.weak 相当于老版本的assign,strong相当于retain对工程中的单个文件制定不使用ARC的方法:在targets的build phases选项下Compile Sources下选择要不使用arc编译的文件,双击它,输入-fno-objc-arc即可
TA的推荐TA的最新馆藏[转]&[转]&
喜欢该文的人也喜欢在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
在iOS MRC下,把NSInteger转化为id,可以直接强转,(id)UIDeviceOrientationLandscapeLeft,然后就可以performselector withobject,
现在我在ARC下同样的代码就会报disallowed的错误,那要怎么转化呢?前提我不想用mrc,那些关掉ARC的方式就算了,也不想用NSInvocation,麻烦,求助!
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
NSInteger a = 1;
id b = @(a);
b为NSNumber类型
友情提示:强制转换是有问题的
同步到新浪微博
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。转向ARC的说明
ARC是一个编译器特征,它提供了对OC对象自动管理内存。ARC让开发者专注于感兴趣的代码和对象的关系,而不用考虑对象的retain和release。
原文:T(苹果官方文档)
ARC是一个编译器特征,它提供了对OC对象自动管理内存。ARC让开发者专注于感兴趣的代码和对象的关系,而不用考虑对象的retain和release。
ARC在编译时期添加代码,保证对象可用。概念上说,ARC遵循手动引用计数的规则,替开发者,在编译时期添加合适的代码。
Xcode4.2(Mac OS 10.6、10.7和iOS4和iOS5)支持ARC,弱引用在10.6和iOS4上不支持。
Xcode提供了一个工具:自动机械得转化为ARC(比如移除retain和release的调用),并帮助开发者解决不能自动迁移的问题。迁移工具将所有文件转化成ARC,开发者也可以对单个文件实施ARC,方便于开发者对某些文件手动引用计数。
ARC评估了对象的生命周期,并自动插入合适的代码在编译时期,从而代替开发者不得不考虑何时需要retain、release和autolease。同编译器替开发者,生成合适的dealloc方法。一般来说,当开发者需要在手动引用计数和ARC配合使用时候,使用传统ARC的Cocoa命名惯例是很重要的。
一个正确的完整的Person类如下:
@interface&Person&:&NSObject&&&@property&NSString&*firstN&&&@property&NSString&*lastN&&&@property&NSNumber&*yearOfB&&&@property&Person&*&&&@end&&&&&&&@implementation&Person&&&@end&&&
对象的属性默认是strong;strong属性在 &ARC Introduces New Lifetime Qualifiers.&有描述
-&(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类的方法takeLastNameFrom:
-&(void)takeLastNameFrom:(Person&*)person&{&&&&&&&NSString&*oldLastname&=&[self&lastName];&&&&&&&[self&setLastName:[person&lastName]];&&&&&&&NSLog(@&Lastname&changed&from&%@&to&%@&,&oldLastname,&[self&lastName]);&&&}&&&
ARC确保oldLastName在NSLog之前不会被销毁。
ARC执行了新的规则
ARC执行了一些新的规则,是其他编译模式没有的。这个规则是:致力于提供一个安全可靠的内存管理模式。在某些情况下,他们只是执行最佳实践;某些情况,他们简化你的代码或者处理那没明显的不需要内存问题。如果你违反这些规则,立即得到一个编译错误,而不会在运行显示一个微妙的bug。
●&开发者不能显示调用dealloc;不能实现和调用retain、release、retainCount和autorelease。
禁止使用@selector(retain),@selector(release)等等。
开发者仍可以实现dealloc方法,如果你想管理资源而不是变量。开发者不能release变量,但是可以调用[systemClassInstance setDelegate:nil]在系统类上,或者其他不是用ARC编译的代码上。
ARC中自定义的dealloc方法,不需要调用[super dealloc](其实这样做就会导致编译错误),编译器会强制自动链接到父类。
开发者仍可以对Core Foundation-style对象,使用CFRetain,CFRelease和其他相关方法。
● 不能使用NSAllocateObject或者NSDeallocateObject。开发者创建对象使用alloc,运行时环境负责销毁对象。
● 在C数据结构中,不能使用对象指针。可以使用OC类来代替C的struct
● id和void*没有自动转换.
开发者必须使用特殊的类型转化.开发者需要通过函数参数传递,在OC对象和Core Foundation之间做类型转换。
● 开发者不能使用NSAutoreleasePool对象。ARC下使用@autoreleasepool,它比NSAtuoreleasePool更有效率。
● 开发者不能使用内存zones。不用再使用NSZone了。他们已经被现代的OC运行环境给忽略了。
为了配合手动引用计数,ARC的方法命名有限制:
● 访问器方法不能已new开头,反过来就是:开发者不能声明一个已new开头的属性,除非你给你指定一个getter
&@property&NSString&*newT&&&&&&&&@property&(getter=theNewTitle)&NSString&*newT&&&
ARC引入了新的Lifetime修饰符。
ARC引入几个新的修饰符和弱(weak)引用。弱引用不会延伸到对象生命周期,并自动设置为nil,当该对象没有任何的强引用的时候。
开发者需要使用这些修饰来管理对象图。通常ARC不对循环引用做警告。谨慎得使用弱引用可以保证不会循环引用。
Property属性
weak和strong关键字作为新的property属性被引入,例如:
&@property(strong)&MyClass&*myO&&&&&&&&&&@property(weak)&MyClass&*myO&&&
ARC下,strong是默认property属性
变量的修饰符
开发者使用下面得lifetime修饰。
__unsafe_unretained
__autoreleasing
● 默认是__strong。只要对象还有强引用,该对象&活着&。
● __weak不保留对象,只是简单引用。weak对象将被设置nil,当对象没有任何强引用的时候。
● __unsafe_unretained 不保留对象,只是简单引用。但是不设置为nil,当对象没有任何强引用得时候。如果对象被销毁,__unsafe_unretained的对象将会野指针。
● __autoreleasing 用于标识id*的引用参数,或者需要自动释放的返回的对象。
开发者需要正确修饰变量。使用下面的格式来修饰变量声明。
类名* &修饰 &变量名
MyClass&*&__weak&myWeakR&&&MyClass&*&__unsafe_unretained&myUnsafeR&&&
其他的变种在技术上是不正确的,但可能可以通过编译。了解更多http://cdecl.org/
在栈上小心使用__weak。考虑下面的代码:
NSString&*&__weak&string&=&[[NSString&alloc]&initWithFormat:@&First&Name:&%@&,&[self&firstName]];&&&NSLog(@&string:&%@&,&string);&&&
尽管string在初始化后被使用了。但是,由于在赋值的时候没有强引用;因此它将立即被销毁。
开发者同样需要注意传递引用的地方,例如下面的代码:
NSError&*&&&BOOL&OK&=&[myObject&performOperationWithError:&error];&&&if&(!OK)&{&&&&&&&&&&&&&
然而,这种错误是隐含的。
NSError&*&__strong&e;&&&
并且声明的方法可能是下面这样:
-(BOOL)performOperationWithError:(NSError&*&__autoreleasing&*)&&&
编译器将重写代码:
NSError&*&__strong&&&&NSError&*&__autoreleasing&tmp&=&&&&BOOL&OK&=&[myObject&performOperationWithError:&tmp];&&&error&=&&&&if&(!OK)&{&&&&&&&&&&&&&
本地变量声明(__strong)和参数(__autoreleasing)导致编译器创建临时变量。当开发者对__strong对象取地址,将参数声明为id __strong*,就得到原始的指针。或者开发者可以将变量声明为__autoreleasing
使用Lifetime修饰符,避免循环引用
开发者可以通过lifetime修饰符来避免循环引用。例如,如果你有一个对象图(关于父-子继承)。并且父类需要引用子类,相反子类也要用。这时候,开发者把parent-to-child写做strong并把child-to-parent关系写作weak。其他情况可能有些麻烦,特别是调用block变量的时候。
手动引用计数模式下,__block id x 这样的写法,不会对x进行retain。在ARC模式,__默认retain x(就像其他变量一样)。如果想在ARC模式下,得到手动引用计数的效果,开发者可以使用__unsafe_unretained __block id x。顾名思义,__unsafe_unretained __block id x是危险的(因为他可能导致野指针)因此也不建议使用。好的解决方案是:使用__weak或者将__block的值设置为nil,来打断retain循环。
下面的代码段展示了如何使用手动引用计数
MyViewController&*myController&=&[[MyViewController&alloc]&init&];&&&&myController.completionHandler&=&&^(NSInteger&result)&{&&&&&&[myController&dismissViewControllerAnimated:YES&completion:nil];&&&};&&&[self&presentViewController:myController&animated:YES&completion:^{&&&&&&[myController&release];&&&}];&&&
正如说的那样,开发者可以使用__block修饰符并且设置myController变量为nil,在完成处理的时候。
MyViewController&*&__block&myController&=&[[MyViewController&alloc]&init&];&&&&myController.completionHandler&=&&^(NSInteger&result)&{&&&&&&&[myController&dismissViewControllerAnimated:YES&completion:nil];&&&&&&&myController&=&&&&};&&&
或者,你可以使用临时的__weak变量。下面是一个简单的实现
MyViewController&*myController&=&[[MyViewController&alloc]&init&];&&&&MyViewController&*&__weak&weakMyViewController&=&myC&&&myController.completionHandler&=&&^(NSInteger&result)&{&&&&&&&[weakMyViewController&dismissViewControllerAnimated:YES&completion:nil];&&&};&&&
对于non-trivial循环,开发者应该使用下面代码:
MyViewController&*myController&=&[[MyViewController&alloc]&init&];&&&&MyViewController&*&__weak&weakMyController&=&myC&&&myController.completionHandler&=&&^(NSInteger&result)&{&&&&&&&MyViewController&*strongMyController&=&weakMyC&&&&&&&if&(strongMyController)&{&&&&&&&&&&&&&&&&&&&&[strongMyController&dismissViewControllerAnimated:YES&completion:nil];&&&&&&&&&&&&&&&&}&&&&&&&else&{&&&&&&&&&&&&&&&&}&&&};&&&
在某些情况,开发者使用__unsafe_unretained,如果类本身不是__weak修饰。然而,这样将变得不切合实际了,因为它可能很难或者不可能去验证:__unsafe_unretained的指针仍然可用并且指向某些变量。
ARC使用一个新语句管理Autorelease Pools
使用ARC,开发者不能直接使用NSAutoreleasePool来管理autorelease pools。而使用@autoreleasepool代替它。
@autoreleasepool&{&&&&&&&&&}&&&
这个简单的结构允许编译器思考引用计数的状态。进入的时候,自动释放池被push。在正常退出的时候自动释放池配poped出来。为了配合现有代码,如果代码异常退出,自动释放池将不会pop出来。它比NSAutoreleasePool更有效率;因此建议开发者替换NSAtuoreleasePool。
Patterns for Managing Outlets Become Consistent Across Platforms(略)
栈变量被初始化为nil
使用ARC,strong、weak和autoreleasing栈变量将不会显示初始化为nil,例如:
-&(void)myMethod&{&&&&&&&NSString&*&&&&&&&NSLog(@&name:&%@&,&name);&&&}&&&
将打印出null,而不是崩溃。
使用编译器选项来开启和关闭ARC
开发者使用-fobjc-arc 编译选项开启ARC,还可以对某一个文件使用ARC,便于在使用手动引用计数的文件中使用ARC。对于已经使用ARC的工程,仍可以指定一个文件来关闭ARC通过-fno-objc-arc编译选项。
管理Toll-Free Bridging
在多数的Cocoa程序中,开发者需要使用Core Foundaton-style对象,无论是从Core Foundation框架还是从Core foundation的其他框架比如Core Graphics。
编译器不会自动管理Core foundation对象的生命周期。开发者必须根据COreFoundation的内存管理规则,使用CFRetain和CFRelease。
如果开发者在OC和Core foundation两种对象做转换,需要告诉编译器对象的所有权。
● __bridge 不改变所有权的情况下,将OC和Core foundaton对象之间转换。
● __bridge_retained 或者 CFBridgingRetain 或者对象的所有权,将OC和Corefoundaton对象之间转换。开发者仍有责任将释放对象通过CFRelease。
● __bridge_transfer 或者CFBridgingRelease将一个非OC指针,转化为OC指针,ARC负责释放对象。
例如,现有代码:
-&(void)logFirstNameOfPerson:(ABRecordRef)person&{&&&&&&&&&&&NSString&*name&=&(NSString&*)ABRecordCopyValue(person,&kABPersonFirstNameProperty);&&&&&&&NSLog(@&Person's&first&name:&%@&,&name);&&&&&&&[name&release];&&&}&&&
开发用下面的代码代替
-&(void)logFirstNameOfPerson:(ABRecordRef)person&{&&&&&&&&&&&NSString&*name&=&(NSString&*)CFBridgingRelease(ABRecordCopyValue(person,&kABPersonFirstNameProperty));&&&&&&&NSLog(@&Person's&first&name:&%@&,&name);&&&}&&&
编译器处理从COcoa方法返回的 CF 对象
编译器知道返回Core foundaion类的OC的方法,遵循历史的规定。例如,编译器知道从CGColor方法返回的GCColor是不拥有的。开发者必须使用合适的类型去转化。例如:
NSMutableArray&*colors&=&[NSMutableArray&arrayWithObject:(id)[[UIColor&darkGrayColor]&CGColor]];&&&[colors&addObject:(id)[[UIColor&lightGrayColor]&CGColor]];&&&
使用所有权关键字转化函数参数
当开发者在OC和Core foundation的对象之间转化时,需要告诉编译器传递object的所有权。Core foundation对象所有权的规则在CoreFoundation的内存管理规则中。OC的所有权规则在Advanced Memory Management Programming Guide中。
下面的代码段,数组传递给CGGradientCreateWithCorlors函数需要一个合适的转化。数组是arrayWitshObjects返回的,所以,不要将所有权传递给函数,因此使用__bridge
NSArray&*colors&=&&#An&array&of&colors#&;&&&CGGradientRef&gradient&=&CGGradientCreateWithColors(colorSpace,&(__bridge&CFArrayRef)colors,&locations);&&
下面代码段实现了一个context,使用Core Foundation内存管理的方法。
-&(void)drawRect:(CGRect)rect&{&&&&&&&CGContextRef&ctx&=&UIGraphicsGetCurrentContext();&&&&&&&CGColorSpaceRef&colorSpace&=&CGColorSpaceCreateDeviceGray();&&&&&&&CGFloat&locations[2]&=&{0.0,&1.0};&&&&&&&NSMutableArray&*colors&=&[NSMutableArray&arrayWithObject:(id)[[UIColor&darkGrayColor]&CGColor]];&&&&&&&[colors&addObject:(id)[[UIColor&lightGrayColor]&CGColor]];&&&&&&&CGGradientRef&gradient&=&CGGradientCreateWithColors(colorSpace,&(__bridge&CFArrayRef)colors,&locations);&&&&&&&CGColorSpaceRelease(colorSpace);&&&&&&&CGPoint&startPoint&=&CGPointMake(0.0,&0.0);&&&&&&&CGPoint&endPoint&=&CGPointMake(CGRectGetMaxX(self.bounds),&CGRectGetMaxY(self.bounds));&&&&&&&CGContextDrawLinearGradient(ctx,&gradient,&startPoint,&endPoint,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&kCGGradientDrawsBeforeStartLocation&|&kCGGradientDrawsAfterEndLocation);&&&&&&&CGGradientRelease(gradient);&&&}&&&
将工程转化为ARC,遇到的常见问题
当迁移现有的项目,你可能会遇到的各种问题。这里有一些共同的问题,共同解决方案。
● 不能调用retain,release或者autorelease,这是一种特性,甚至可以这么写:
while&([x&retainCount])&{&[x&release];&}&&&
● 不能调用dealloc
通常,开发者在单例的实现或者替换一个对象的init方法的时候调用dealloc。对于单例模式,使用共享实例模式。在init方法中,你不用调用dealloc,因为对象会被释放,当重写self的时候。
● 不能使用NSAutoreleasePool对象
表格@autoreleasepool{}代替NSAutoreleasePool.这将强制一个block处于一个自动释放池中。它比NSAutoreleaePool快6倍。@autoreleasepool也在在非ARC模式下工作。
● ARC需要开发者对[super init]赋值给self在init方法中。
下面代码是不可行的
[super&init];&&&
简单的修正是:
self&=&[super&init];&&&
根号的修复是这样的
self&=&[super&init];&&&if&(self)&{&&&&&&...&&&
● 不能实现retain和release方法。
实现自定义的retain和release方法打破弱指针。提供了几个常用的 &实现自定义&的原因。
不要这么做,NSObject的retain和release已经很快了。如果你发现仍有问题,请提出这个bug
2.实现一个自定义的弱指针系统
使用__weak代替
3.实现单例
使用shared instance pattern代替。或者使用类来代替方法,避免分配对象。
● assigned 将变成strong
在ARC之前,变量的assigned的不会延伸到对象的生命周期。为了让property变成强引用,开发者通常实例化或者synthesized访问器方法,里面是内存管理方法。相比之下,你可以这样实现访问器方法:
@interface&MyClass&:&Superclass&{&&&&&&&id&&&}&&&&@end&&&&&&&@implementation&MyClass&&&-&(id)thing&{&&&&&&&return&&&&}&&&-&(void)setThing:(id)newThing&{&&&&&&&thing&=&newT&&&}&&&&@end&&&
ARC下,实例中的变量默认是strong引用,assigning一个对象给实例中的变量延伸到对象的生命周期。迁移工具不能决定一个实例变量即将weak。保持相同的行为之前,你必须标记实例变量是weak,或声明它的property
@interface&MyClass&:&Superclass&{&&&&&&&id&__weak&&&&}&&&&@end&&&&&&&@implementation&MyClass&&&-&(id)thing&{&&&&&&&return&&&&}&&&-&(void)setThing:(id)newThing&{&&&&&&&thing&=&newT&&&}&&&&@end&&&
@interface&MyClass&:&Superclass&&&@property&(weak)&id&&&&&@end&&&&&&&@implementation&MyClass&&&@synthesize&&&&&@end&&&
● 不能使用strong ids在c的数据结构
例如,下面的c结构将不能编译过
struct&X&{&id&x;&float&y;&};&&&
这是因为x默认是strong retain,但是,在正常运行情况下,编译器不能安全的合成所有需要的代码。比如:如果你传递一个指针给x或者y后,执行了free,每一个id将被release掉,在struct被free之前。编译器不能可靠的做这些。所以strong ids在结构,在ARC中完全不允许。下面是一些解决方案:
1.用OC类代替c结构。这应该是最好的解决办法。
2.如果使用OC类是次要的方法(可能你想要一个高密度的结构数组),那么考虑使用void*代替。这需要使用显示的转化。
3.把对象引用作为__unsafe_unretained。这种方法是半常见的模式,这样是有用的。
struct&x&{&NSString&*S;&&int&X;&}&StaticArray[]&=&{&&&&&@&foo&,&42,&&&&&@&bar,&97,&&&...&&&};&&&
开发者这样声明
struct&x&{&NSString&*&__unsafe_unretained&S;&int&X;&}&&&
这可能是有问题的,如果对象可以被释放时指针是不安全的,但它是非常有用的东西,被称为是字符串常量。
● 不能直接将id和void*进行转化(包含Core Foundation类型)参考Managing Toll-Free Bridging
经常遇到的问题
我该怎样认识ARC?它在哪儿放置retains/releases。
不要想什么地方调用retain/release,考虑程序本身算法吧。考虑&strong and weak&关系,对象的所有权关系和可能存在的循环引用。
我还需要写dealloc方法么
可能需要。因为ARC不会自动对 Core Foundation 对象,文件描述符等等进行malloc/free,,这些资源扔需要写dealloc方法。
不不能release对象的变量,但是可以调用[self setDelegate:nil]在系统的类和其他不用ARC的代码。
ARC种 不需要dealloc方法,或者[super dealloc];在运行时系统调用super代码。
在ARC种,仍存在循环引用?
是的。ARC自动retain/release并可能继承了循环引用的问题。幸运的是:迁移到ARC的代码很少泄露,因为无论properties是不是retain的,都被被声明为retain了。
在ARC种blocks是如何工作的
Block能正常工作,当你在栈上传递的时候,比如作为返回值。你无需block copy了。当你传递block在栈下面的时候,添加到arrayWithObjects等需要retain的地方,需要使用[^{ }copy]。
有一件事情需要清除:NSString *__block myString是retain在ARC模式种,不可能是野指针。为了得到以前的行为,使用__block NSString *__unsafe_unretained myString 或者使用__block NSString *__weak myString.
我可以在雪豹OS种开发中使用ARC么?
不行。雪豹版本的Xcode4.2不支持ARC。
ARC下,可以创建C语言的retain的指针数组么
&__strong&SomeClass&**dynamicArray&=&(__strong&SomeClass&**)calloc(entries,&sizeof(SomeClass&*));&&&for&(int&i&=&0;&i&&&&i++)&{&&&&&&&&dynamicArray[i]&=&[[SomeClass&alloc]&init];&&&}&&&&&&&&for&(int&i&=&0;&i&&&&i++)&{&&&&&&&&dynamicArray[i]&=&&&&}&&&free(dynamicArray);&&&
下面是一些注意的地方:
● 你要写__strong SomeClass **在某些情况,默认情况是__autoreleasing SomeClass **.
● 开辟的内存必须是零填充
● 需要设置每一项为nil在释放array的时候(memset和bzero不好使的)
取决于你怎么测量,通常是不慢。编译器消除很多无关紧要的retain/release调用。投入很大的努力在加快OC下的运行环境。尤其是返回一个retian/autoreleased对象,ARC并不是真正将它放到自动释放池。
有一件事需要清除:优化器不在debug模式下。所以想看到更多的retain/release的调用,使用-O0比-Os
ARC在ObjC++模式下工作么?
是的,甚至可以将strong/weakids在类和容器中。ARC编译器合成retain/release逻辑在拷贝构造函数和析构函数钟。
哪些类不支持weak引用?
下面的类不能创建弱引用:
NSATSTypesetter, NSColorSpace, NSFont, NSMenuView, NSParagraphStyle, NSSimpleHorizontalTypesetter, and NSTextView.
对于声明properties时,你应该使用retain代替weak。对于变量你应该使用__unsafe_unretained代替__weak.另外,你不能创建这些类的弱引用:NSHashTable, NSMapTable, or NSPointerArray&
对NSCell和其他类使用NSCopyObject时候。
没什么特别的。ARC负责的显示retain的场景。ARC模式下,所有的copy方法应该仅仅copy实例变量。
我可以对某个文件不使用ARC么?
是的。当开发者迁移工程到ARC时,对所有OC源文件设置为-fobjc-arc编译选项。开发者可以指定一个文件设置-fno-objc-arc编译选项。
GC(Grabage Collection)在mac上过时了?
Grabage Collection在10.8上已经过时,将来会重OS X中移除。ARC将是收推荐的替代技术。为了帮助迁移现有程序,ARC迁移工具在Xcode &=4.3 支持将GC迁移到ARC。
CocoaChina是全球最大的苹果开发中文社区,官方微信每日定时推送各种精彩的研发教程资源和工具,介绍app推广营销经验,最新企业招聘和外包信息,以及Cocos2d引擎、Cocos Studio开发工具包的最新动态及培训信息。关注微信可以第一时间了解最新产品和服务动态,微信在手,天下我有!
请搜索微信号“CocoaChina”关注我们!
关注微信 每日推荐
扫一扫 浏览移动版}

我要回帖

更多关于 苹果id激活锁解除 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信