IOS 5编程 内存管理 ARC技术概述
2013-11-21 10:51
477 查看
ARC(AutomaticReferenceCounting )技术概述
此文章由Tom翻译,首发于csdn的blog,任何人都可以转发,但是请保留原始链接和翻译者得名字。多谢!AutomaticReferenceCounting(ARC)是一个编译期的技术,利用此技术可以简化Objective-C编程在内存管理方面的工作量。
这里我把此技术翻译为自动内存计数器管理技术,下图是使用和不使用此技术的Objective-C代码的区别。
ARC技术是随着XCode4.2一起发布的,在缺省工程模板中,你可以指定你的工程是否支持ARC技术,如果你不指定工程支持ARC技术,在代码中你必须使用管理内存的代码来管理内存。
概述
自动计数(ARC)是一个编译期间工作的能够帮你管理内存的技术,通过它,程序人员可以不需要在内存的retain,释放等方面花费精力。ARC在编译期间为每个Objective-C指针变量添加合适的retain,release,autorelease等函数,保存每个变量的生存周期控制在合理的范围内,以期实现代码上的自动内存管理。
Inorderforthecompilertogeneratecorrectcode,ARCimposessomerestrictionsonthemethodsyoucanuse,andonhowyouusetoll-freebridging(see “Toll-Free
BridgedTypes”);ARCalsointroducesnewlifetimequalifiersforobjectreferencesand declaredproperties.
你可以使用编译标记
-fobjc-arc来让你的工程支持ARC。ARC在Xcode4.2中引入,在MacOSXv10.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 |
IntroducesNewLifetimeQualifiers.”)
使用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 “Practical
MemoryManagement”).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.
__weakspecifiesazeroingweak
referencetoanobject.
__unsafe_unretainedspecifiesweakreferencetoanobjectthatisnotzeroing—iftheobjectitreferencesisdeallocated,thepointer
isleftdangling.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; |
weak.
Ifatableviewcontainsanimageviewandatextview,thentheseremainvalidsolongastheyaresubviewsofthetableviewcellitself.
Outletsshouldbechangedto
strongwhentheoutletshouldbeconsideredtoownthereferencedobject:
Asindicatedpreviously,thisoftenthecasewithFile’sOwner:toplevelobjectsinanibfilearefrequentlyconsideredtobeownedbytheFile’sOwner.
Youmayinsomesituationsneedanobjectfromanibfiletoexistoutsideofitsoriginalcontainer.Forexample,youmighthaveanoutletforaviewthatcanbetemporarilyremovedfromitsinitialviewhierarchyandmustthereforebemaintainedindependently.
其他的新功能
使用ARC技术,可以使得在栈上分配的指针隐式的初始化为nil,比如-(void)myMethod{ |
NSString*name; |
NSLog(@"name:%@",name); |
} |
相关文章推荐
- 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 5编程 内存管理 ARC技术概述
- iOS 5编程 内存管理 ARC技术概述
- iOS 5编程 内存管理 ARC技术概述
- IOS 5编程 内存管理 ARC技术概述
- IOS 5编程 内存管理 ARC技术概述
- IOS内存管理 ARC技术概述
- IOS内存管理 ARC技术概述 .
- IOS内存管理 ARC技术概述
- IOS内存管理 ARC技术概述
- IOS内存管理 ARC技术概述 .
- iOS开发ARC内存管理技术要点