IOS内存管理 ARC技术概述 .
2013-01-23 14:46
483 查看
转自:http://blog.csdn.net/weiqubo/article/details/8108024
这里我把此技术翻译为自动内存计数器管理技术,下图是使用和不使用此技术的Objective-C代码的区别。
ARC技术是随着XCode4.2一起发布的,在缺省工程模板中,你可以指定你的工程是否支持ARC技术,如果你不指定工程支持ARC技术,在代码中你必须使用管理内存的代码来管理内存。
自动计数(ARC)是一个编译期间工作的能够帮你管理内存的技术,通过它,程序人员可以不需要在内存的retain,release等方面花费精力。
ARC在编译期间为每个Objective-C指针变量添加合适的retain,release,autorelease等函数,保存每个变量的生存周期控制在合理的范围内,以期实现代码上的自动内存管理。
Inorderforthecompilertogeneratecorrectcode,ARCimposessomerestrictionsonthemethodsyoucanuse,andonhowyouusetoll-freebridging(see “Toll-Free
BridgedTypes”);ARCalsointroducesnewlifetimequalifiersforobjectreferencesand declaredproperties.
你可以使用编译标记
如果你现在的工程不支持ARC技术,你可以通过一个自动转换工具来转换你的工程(工具在Edit->Convertmenu),这个工具会自动所有工程中手动管理内存的点转换成合适自动方式的(比如移除retain,release等)。这个工具会转换工程中所有的文件。当然你可以转换单个文件。
ARC使得你不需要再思考何时使用retain,release,autorelease这样的函数来管理内存,它提供了自动评估内存生存期的功能,并且在编译期间自动加入合适的管理内存的方法。编译器也会自动生成dealloc函数。一般情况下,通过ARC技术,你可以不顾传统方式的内存管理方式,但是深入了解传统的内存管理是十分有必要的。
下面是一个person类的一个声明和实现,它使用了ARC技术。
(有关strong的帮助,请参考 “ARCIntroducesNewLifeti
4000
meQualifiers.”)
使用ARC,你可以象下面的方式实现contrived函数:
ARC管理内存,所以这里你不用担心aPerson和NSNumber的临时变量会造成内存泄漏。
你还可以象下面的方式来实现Person类中的takeLastNameFrom:方法,
ARC可以保证在NSLog调用的时候,oldLastname还存在于内存中。
为了ARC能顺利工作,特增加如下规则,这些规则可能是为了更健壮的内存管理,也有可能为了更好的使用体验,也有可能是简化代码的编写,不论如何,请不要违反下面的规则,如果违反,将会得到一个编译期错误。
下面的这些函数:
你可能会实现一个和内存管理没有关系的dealloc,譬如只是为了调用
你不可以使用
不能在C语言中的结构中使用Objective-c中的类的指针。
请使用类类管理数据。
不能使用memoryzones.
ARC在函数和便利变量命名上也有一些新的规定
禁止以new开头的属性变量命名。
ARCintroducesseveralnewlifetimequalifiersforobjects,and zeroingweakreferences.Aweakreferencedoesnotextendthelifetimeof
theobjectitpointsto.Azeroingweakreferenceautomaticallybecomes
Youshouldtakeadvantageofthesequalifierstomanagetheobjectgraphsinyourprogram.Inparticular,ARCdoesnotguardagainst strongreferencecycles (previously
knownasretaincycles—see “PracticalMemoryManagement”).Judicioususeofweakrelationshipswillhelptoensureyoudon’tcreatecycles.
zeroingweakreferencetoanobject.
thepointerisleftdangling.Youuse
Takecarewhenusing
Although
deallocated.Thelogstatementshowsthat
Youalsoneedtotakecarewithobjectspassedbyreference.Thefollowingcodewillwork:
However,theerrordeclarationisimplicitly:
andthemethoddeclarationwouldtypicallybe:
Thecompilerthereforerewritesthecode:
Themismatchbetweenthelocalvariabledeclaration(
causesthecompilertocreatethetemporaryvariable.Youcangettheoriginalpointerbydeclaringtheparameter
a
strongandthechild-to-parentrelationshipweak.Othersituationsmaybemoresubtle,particularlywhentheyinvolve blockobjects.
Inmanualreferencecountingmode,
InARCmode,
likeallothervalues).TogetthemanualreferencecountingmodebehaviorunderARC,youcoulduse
however,havinganon-retainedvariableisdangerous(becauseitcandangle)andisthereforediscouraged.Twobetteroptionsaretoeitheruse
don’tneedtosupportiOS 4orOS X v10.6),orsetthe
breaktheretaincycle.
Thefollowingcodefragmentillustratesthisissueusingapatternthatissometimesusedinmanualreferencecounting.
Asdescribed,instead,youcanusea
to
Alternatively,youcanuseatemporary
Fornon-trivialcycles,however,youshoulduse:
Insomecasesyoucanuse
Thiscan,however,becomeimpracticalfornontrivialcyclesbecauseitcanbehardorimpossibletovalidatethatthe
andstillpointstothesameobjectinquestion.
使用ARC,你不能使用
编译器根据工程是否使用ARC,来决定这个语法结构最终呈现方式,这个语法结构使用了一种比
Thepatternsfordeclaring outlets iniOSandOS XchangewithARCandbecomeconsistentacrossbothplatforms.Thepatternyoushould typically adoptis:outletsshouldbe
exceptforthosefromFile’sOwnertotop-levelobjectsinanibfile(orastoryboardscene)whichshouldbe
Outletsthatyoucreateshouldwillthereforegenerallybe
Outletsthatyoucreateto,forexample,subviewsofaviewcontroller’svieworawindowcontroller’swindow,arearbitraryreferencesbetweenobjectsthatdonotimplyownership.
The
or
Forexample:
Incaseswhereyoucannotcreateaweakreferencetoaninstanceofaparticularclass(suchas
than
Thispatternextendstoreferencesfromacontainerviewtoitssubviewswhereyouhavetoconsiderthe internal consistencyofyourobjectgraph.Forexample,inthecaseofatableviewcell,outletstospecificsubviewsshouldagaintypically
be
Outletsshouldbechangedto
Asindicatedpreviously,thisoftenthecasewithFile’sOwner:toplevelobjectsinanibfilearefrequentlyconsideredtobeownedbytheFile’sOwner.
Youmayinsomesituationsneedanobjectfromanibfiletoexistoutsideofitsoriginalcontainer.Forexample,youmighthaveanoutletforaviewthatcanbetemporarilyremovedfromitsinitialviewhierarchyandmustthereforebemaintainedindependently.
使用ARC技术,可以使得在栈上分配的指针隐式的初始化为nil,比如
上面的代码会Log出来一个null,不会象不使用ARC技术的时候使得程序崩溃。
ARC工作原理是在编译程序的时候由xCode将内存操作的代码(如:retain,release和autorelease)自动添加到需要的位置。
ARC只能在iOS4和iOS5上使用,weakrefrences只能在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方法里面去掉[superdealloc]方法,在ARC下父类的dealloc同样由编译器来自动完成
3.CoreFoundation类型的对象任然可以用CFRetain,CFRelease这些方法
4.不能在使用NSAllocateObject和NSDeallocateObject对象
5.不能在c结构体中使用对象指针,如果有类似功能可以创建一个Objective-c类来管理这些对象
6.在id和void*之间没有简便的转换方法,同样在Objective-c和coreFoundation类型之间的转换都需要使用编译器制定的转换函数
7.不能再使用NSAutoreleasePool对象,ARC提供了@autoreleasepool块来代替它,这样更加有效率
8.不能使用内存存储区(不能再使用NSZone)
9.不能以new为开头给一个属性命名
10.声明outlet时一般应当使用weak,除了对StoryBoard这样nib中间的顶层对象要用strong
11.weak相当于老版本的assign,strong相当于retain
对工程中的单个文件制定不使用ARC的方法:在targets的buildphases选项下CompileSources下选择要不使用arc编译的文件,双击它,输入
ARC(AutomaticReferenceCounting )技术概述
AutomaticReferenceCounting(ARC)是一个编译期的技术,利用此技术可以简化Objective-C编程在内存管理方面的工作量。这里我把此技术翻译为自动内存计数器管理技术,下图是使用和不使用此技术的Objective-C代码的区别。
ARC技术是随着XCode4.2一起发布的,在缺省工程模板中,你可以指定你的工程是否支持ARC技术,如果你不指定工程支持ARC技术,在代码中你必须使用管理内存的代码来管理内存。
概述
自动计数(ARC)是一个编译期间工作的能够帮你管理内存的技术,通过它,程序人员可以不需要在内存的retain,release等方面花费精力。ARC在编译期间为每个Objective-C指针变量添加合适的retain,release,autorelease等函数,保存每个变量的生存周期控制在合理的范围内,以期实现代码上的自动内存管理。
Inorderforthecompilertogeneratecorrectcode,ARCimposessomerestrictionsonthemethodsyoucanuse,andonhowyouusetoll-freebridging(see “Toll-Free
BridgedTypes”);ARCalsointroducesnewlifetimequalifiersforobjectreferencesand declaredproperties.
你可以使用编译标记
-fobjc-arc
来让你的工程支持ARC。ARC在Xcode4.2中引入,在Mac OSXv10.6,v10.7(64位应用),iOS4,iOS5中支持,Xcode4.1中不支持这个技术.
如果你现在的工程不支持ARC技术,你可以通过一个自动转换工具来转换你的工程(工具在Edit->Convertmenu),这个工具会自动所有工程中手动管理内存的点转换成合适自动方式的(比如移除retain,release等)。这个工具会转换工程中所有的文件。当然你可以转换单个文件。
ARC提供自动内存管理的功能
ARC使得你不需要再思考何时使用retain,release,autorelease这样的函数来管理内存,它提供了自动评估内存生存期的功能,并且在编译期间自动加入合适的管理内存的方法。编译器也会自动生成dealloc函数。一般情况下,通过ARC技术,你可以不顾传统方式的内存管理方式,但是深入了解传统的内存管理是十分有必要的。下面是一个person类的一个声明和实现,它使用了ARC技术。
@interfacePerson:NSObject |
@property(nonatomic,strong)NSString*firstName; |
@property(nonatomic,strong)NSString*lastName; |
@property(nonatomic,strong)NSNumber*yearOfBirth; |
@property(nonatomic,strong)Person*spouse; |
@end |
@implementationPerson |
@synthesizefirstName,lastName,yearOfBirth,spouse; |
@end |
4000
meQualifiers.”)
使用ARC,你可以象下面的方式实现contrived函数:
-(void)contrived{ |
Person*aPerson=[[Personalloc]init]; |
[aPersonsetFirstName:@"William"]; |
[aPersonsetLastName:@"Dudney"]; |
[aPerson:setYearOfBirth:[[NSNumberalloc]initWithInteger:2011]]; |
NSLog(@"aPerson:%@",aPerson); |
} |
你还可以象下面的方式来实现Person类中的takeLastNameFrom:方法,
-(void)takeLastNameFrom:(Person*)person{ |
NSString*oldLastname=[selflastName]; |
[selfsetLastName:[personlastName]]; |
NSLog(@"Lastnamechangedfrom%@to%@",oldLastname,[selflastName]); |
} |
ARC中的新规则
为了ARC能顺利工作,特增加如下规则,这些规则可能是为了更健壮的内存管理,也有可能为了更好的使用体验,也有可能是简化代码的编写,不论如何,请不要违反下面的规则,如果违反,将会得到一个编译期错误。下面的这些函数:
dealloc,
retain,
release,
retainCount,
autorelease。禁止任何形式调用和实现
(dealloc可能会被实现),包括使用
@selector(retain),
@selector(release)等的隐含调用。
你可能会实现一个和内存管理没有关系的dealloc,譬如只是为了调用
[systemClassInstancesetDelegate:nil],但是请不要调用
[super dealloc],因为编译器会自动处理这些事情。
你不可以使用
NSAllocateObject
或者
NSDeallocateObject.
使用alloc申请一块内存后,其他的都可以交给运行期的自动管理了。
不能在C语言中的结构中使用Objective-c中的类的指针。
请使用类类管理数据。
不能使用NSAutoreleasePool.
作为替代,@autoreleasepool被引入
,你可以使用这个效率更高的关键词。
不能使用memoryzones.
NSZone不再需要—本来这个类已经被现代Objective-c废弃。
ARC在函数和便利变量命名上也有一些新的规定
禁止以new开头的属性变量命名。
ARCIntroducesNewLifetimeQualifiers
ARCintroducesseveralnewlifetimequalifiersforobjects,and zeroingweakreferences.Aweakreferencedoesnotextendthelifetimeoftheobjectitpointsto.Azeroingweakreferenceautomaticallybecomes
niliftheobjectitpointstoisdeallocated.
Youshouldtakeadvantageofthesequalifierstomanagetheobjectgraphsinyourprogram.Inparticular,ARCdoesnotguardagainst strongreferencecycles (previously
knownasretaincycles—see “PracticalMemoryManagement”).Judicioususeofweakrelationshipswillhelptoensureyoudon’tcreatecycles.
属性变量修饰符
weak和strong两个修饰符是新引进的,使用例子如下://下面的作用和:@property(retain)MyClass*myObject;相同 |
@property(strong)MyClass*myObject; |
//下面的作用和"@property(assign)MyClass*myObject;"相识 |
//不同的地方在于,如果MyClass的实例析构后,这个属性变量的值变成nil,而不是一个野指针, |
@property(weak)MyClass*myObject; |
VariableQualifiers
Youusethefollowinglifetimequalifiersforvariablesjustlikeyouwould,say,const.
__strong
__weak
__unsafe_unretained
__autoreleasing
__strongisthedefault.
__weakspecifiesa
zeroingweakreferencetoanobject.
__unsafe_unretainedspecifiesweakreferencetoanobjectthatisnotzeroing—iftheobjectitreferencesisdeallocated,
thepointerisleftdangling.Youuse
__autoreleasingtodenoteargumentsthatarepassedbyreference(
id *)andareautoreleasedonreturn.
Takecarewhenusing
__weakvariablesonthestack.Considerthefollowingexample:
NSString__weak*string=[[NSStringalloc]initWithFormat:@"FirstName:%@",[selffirstName]]; |
NSLog(@"string:%@",string); |
stringisusedaftertheinitialassignment,thereisnootherstrongreferencetothestringobjectatthetimeofassignment;itisthereforeimmediately
deallocated.Thelogstatementshowsthat
stringhasanullvalue.
Youalsoneedtotakecarewithobjectspassedbyreference.Thefollowingcodewillwork:
NSError*error=nil; |
BOOLOK=[myObjectperformOperationWithError:&error]; |
if(!OK){ |
//Reporttheerror. |
//... |
NSError*__stronge=nil; |
-(BOOL)performOperationWithError:(NSError*__autoreleasing*)error; |
NSError__strong*error=nil; |
NSError__autoreleasing*tmp=error; |
BOOLOK=[myObjectperformOperationWithError:&tmp]; |
error=tmp; |
if(!OK){ |
//Reporttheerror. |
//... |
__strong)andtheparameter(
__autoreleasing)
causesthecompilertocreatethetemporaryvariable.Youcangettheoriginalpointerbydeclaringtheparameter
id__strong*whenyoutaketheaddressof
a
__strongvariable.Alternativelyyoucandeclarethevariableas
__autoreleasing.
UseLifetimeQualifierstoAvoidStrongReferenceCycles
Youcanuselifetimequalifierstoavoidstrongreferencecycles.Forexample,typicallyifyouhaveagraphofobjectsarrangedinaparent-childhierarchyandparentsneedtorefertotheirchildrenandviceversa,thenyoumaketheparent-to-childrelationshipstrongandthechild-to-parentrelationshipweak.Othersituationsmaybemoresubtle,particularlywhentheyinvolve blockobjects.
Inmanualreferencecountingmode,
__blockidx;hastheeffectofnotretaining
x.
InARCmode,
__blockidx;defaultstoretaining
x(just
likeallothervalues).TogetthemanualreferencecountingmodebehaviorunderARC,youcoulduse
__unsafe_unretained__blockidx;.Asthename
__unsafe_unretainedimplies,
however,havinganon-retainedvariableisdangerous(becauseitcandangle)andisthereforediscouraged.Twobetteroptionsaretoeitheruse
__weak(ifyou
don’tneedtosupportiOS 4orOS X v10.6),orsetthe
__blockvalueto
nilto
breaktheretaincycle.
Thefollowingcodefragmentillustratesthisissueusingapatternthatissometimesusedinmanualreferencecounting.
MyViewController*myController=[[MyViewControlleralloc]init…]; |
//... |
myController.completionHandler=^(NSIntegerresult){ |
[myControllerdismissViewControllerAnimated:YEScompletion:nil]; |
}; |
[selfpresentViewController:myControlleranimated:YEScompletion:^{ |
[myControllerrelease]; |
}]; |
__blockqualifierandsetthe
myControllervariable
to
nilinthecompletionhandler:
__blockMyViewController*myController=[[MyViewControlleralloc]init…]; |
//... |
myController.completionHandler=^(NSIntegerresult){ |
[myControllerdismissViewControllerAnimated:YEScompletion:nil]; |
myController=nil; |
}; |
__weakvariable.Thefollowingexampleillustratesasimpleimplementation:
MyViewController*myController=[[MyViewControlleralloc]init…]; |
//... |
__weakMyViewController*weakMyViewController=myController; |
myController.completionHandler=^(NSIntegerresult){ |
[weakMyViewControllerdismissViewControllerAnimated:YEScompletion:nil]; |
}; |
MyViewController*myController=[[MyViewControlleralloc]init…]; |
//... |
__weakMyViewController*weakMyController=myController; |
myController.completionHandler=^(NSIntegerresult){ |
MyViewController*strongMyController=weakMyController; |
if(strongMyController){ |
//... |
[strongMyControllerdismissViewControllerAnimated:YEScompletion:nil]; |
//... |
} |
else{ |
//Probablynothing... |
} |
}; |
__unsafe_unretainediftheclassisn’t
__weakcompatible.
Thiscan,however,becomeimpracticalfornontrivialcyclesbecauseitcanbehardorimpossibletovalidatethatthe
__unsafe_unretainedpointerisstillvalid
andstillpointstothesameobjectinquestion.
自动释放池
使用ARC,你不能使用NSAutoReleasePool类来管理自动释放池了,作为替代,ARC使用一个新的语法结构:
@autoreleasepool{ |
//Code,suchasaloopthatcreatesalargenumberoftemporaryobjects. |
} |
NSAutoReleasePool更高效的方式。
Outlets
Thepatternsfordeclaring outlets iniOSandOS XchangewithARCandbecomeconsistentacrossbothplatforms.Thepatternyoushould typically adoptis:outletsshouldbe weak,
exceptforthosefromFile’sOwnertotop-levelobjectsinanibfile(orastoryboardscene)whichshouldbe
strong.
Outletsthatyoucreateshouldwillthereforegenerallybe
weakbydefault:
Outletsthatyoucreateto,forexample,subviewsofaviewcontroller’svieworawindowcontroller’swindow,arearbitraryreferencesbetweenobjectsthatdonotimplyownership.
The
strongoutletsarefrequentlyspecifiedbyframeworkclasses(forexample,
UIViewController’s
viewoutlet,
or
NSWindowController’s
windowoutlet).
Forexample:
@interfaceMyFilesOwnerClass:SuperClass |
@property(weak)IBOutletMyView*viewContainerSubview; |
@property(strong)IBOutletMyOtherClass*topLevelObject; |
@end |
NSTextView),youshoulduse
assignrather
than
weak:
@property(assign)IBOutletNSTextView*textView; |
be
weak.Ifatableviewcontainsanimageviewandatextview,thentheseremainvalidsolongastheyaresubviewsofthetableviewcellitself.
Outletsshouldbechangedto
strongwhentheoutletshouldbeconsideredtoownthereferencedobject:
Asindicatedpreviously,thisoftenthecasewithFile’sOwner:toplevelobjectsinanibfilearefrequentlyconsideredtobeownedbytheFile’sOwner.
Youmayinsomesituationsneedanobjectfromanibfiletoexistoutsideofitsoriginalcontainer.Forexample,youmighthaveanoutletforaviewthatcanbetemporarilyremovedfromitsinitialviewhierarchyandmustthereforebemaintainedindependently.
其他的新功能
使用ARC技术,可以使得在栈上分配的指针隐式的初始化为nil,比如-(void)myMethod{ |
NSString*name; |
NSLog(@"name:%@",name); |
} |
ARC工作原理是在编译程序的时候由xCode将内存操作的代码(如:retain,release和autorelease)自动添加到需要的位置。
ARC只能在iOS4和iOS5上使用,weakrefrences只能在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方法里面去掉[superdealloc]方法,在ARC下父类的dealloc同样由编译器来自动完成
3.CoreFoundation类型的对象任然可以用CFRetain,CFRelease这些方法
4.不能在使用NSAllocateObject和NSDeallocateObject对象
5.不能在c结构体中使用对象指针,如果有类似功能可以创建一个Objective-c类来管理这些对象
6.在id和void*之间没有简便的转换方法,同样在Objective-c和coreFoundation类型之间的转换都需要使用编译器制定的转换函数
7.不能再使用NSAutoreleasePool对象,ARC提供了@autoreleasepool块来代替它,这样更加有效率
8.不能使用内存存储区(不能再使用NSZone)
9.不能以new为开头给一个属性命名
10.声明outlet时一般应当使用weak,除了对StoryBoard这样nib中间的顶层对象要用strong
11.weak相当于老版本的assign,strong相当于retain
对工程中的单个文件制定不使用ARC的方法:在targets的buildphases选项下CompileSources下选择要不使用arc编译的文件,双击它,输入
-fno-objc-arc即可
相关文章推荐
- IOS 5编程 内存管理 ARC技术概述
- IOS 5编程 内存管理 ARC技术概述
- IOS 5编程 内存管理 ARC技术概述
- IOS 5编程 内存管理 ARC技术概述
- IOS内存管理 ARC技术概述
- iOS 5编程 内存管理 ARC技术概述
- iOS 5编程 内存管理 ARC技术概述
- IOS内存管理 ARC技术概述
- IOS内存管理 ARC技术概述 .
- IOS 5编程 内存管理 ARC技术概述
- iOS 5编程 内存管理 ARC技术概述
- IOS 5编程 内存管理 ARC技术概述 .
- iOS 5编程 内存管理 ARC技术概述
- IOS 5编程 内存管理 ARC技术概述
- IOS 5编程 内存管理 ARC技术概述
- iOS 5编程 内存管理 ARC技术概述
- IOS 5编程 内存管理 ARC技术概述 常见问题解答
- IOS 5编程 内存管理 ARC技术概述
- IOS内存管理 ARC技术概述
- iOS开发ARC内存管理技术要点