iOS内存管理--ARC

arc是一个编译特性用来提供自动管理Objective-c的内存。ARC的目的是把你从内存管理的泥潭中解放出来,更多的去关注你要做的事情。
Arc是在编译的时候插入代码来确信让对象能够按需要来存在。ARC同样是以引用计数为基础。你可以选择在以文件或者项目为单位不使用ARC。
但是建议尽量最好使用ARC,首先,编译器为你做内存管理往往比你自己要更优秀,其次,ARC导致的效率损失在UI面前基本可以忽略不计。



ARC有以下强制规则:
1. 你不能显示的调用dealloc,实现或调用retain,release,retainCount,autorelease。
    你可以实现自己的dealloc,目的是为了把代理设置为空,或者编译的时候没有用到ARC的代码。
2. 不能使用NSAllocateObject 和 NSDeallocateObject
3. 不能在C结构体中使用对象指针 ---原因
4. 不能直接转换id 和 void *
5. 不能使用NSAutoreleasePool,被更有效率的@autoreleasepool取代了。
6. 不能直接使用以new开头的accessor,意味着不能使用以new开头的属性,除非你指定一个不同的名字。如下:
//Won't work
@property   NSString  *newTitle;
//Works
@property  ( getter  = theNewTitle) NSString *newTitle;

ARC引入了新的关于变量生命周期的限定词。
__strong 默认的限定符,只要有强指针指向对象,就可以一直存活
__weak  指定一个引用,这个引用不能保持这个引用的对象存活,没有强对象指向它的话,弱引用就会被设置为nil
__unsafe_unretained 这个引用不能保持这个引用的对象存活,没有强对象指向它的话,弱引用就不会被设置为nil,如果它指向的对象释放了的话,这个指针就成为悬挂指针。
__autoreleasing 用来代表通过引用传递并且在返回时自动释放的参数。
必须正确的使用这些限定符。
NSString  *  __weak  string = [[NSString alloc] initWithFormat: @"First Name: %@" , [ self  firstName]];
NSLog( @"string: %@" , string);
这个weak使用就是不恰当的,因为没有任何强指针指向string,string立即就会被释放了。

栈变量都被初始化为nil。

你需要注意通过引用传递的对象。
NSError  *error;
BOOL  OK = [ myObject  performOperationWithError:& error ];

-( BOOL )performOperationWithError:( NSError  *  __autoreleasing  *)error;
这个调用实际的代码是:
NSError  *  __strong  error;
NSError  *  __autoreleasing  tmp =  error ;
BOOL  OK = [ myObject  performOperationWithError:& tmp ];
error = tmp;
因为形式参数是__autorelease和实际参数是__strong,所以编译器会创建临时变量。

ARC需要在你的init方法中 [super init]的返回值赋给你的self
self  = [ super   init ];
if  ( self ) {
}


struct myStruct {id x; float y;}

因为x默认是强类型,编译器不能安全地合成所有以使其正常工作所需的代码。比如你把一个指向该结构的指针传递给别的函数,结构体里面的id必须在结构被free掉之前释放,但是编译器不能可靠的做到这些。因此在ARC中不能在结构体中使用强对象。可以使用以下解决方案:
1. 使用Objective-C Objects 代替结构体,这是最好的方式

2  使用void*替代。

3. 使用_unsafe_unretained限定符来比标示对象引用
struct myStruct {NSString *__unsafe_unretained s; float y;}
当然这可能是有问题的,是不安全的,如果该对象能从指针下被释放。但是它对那些像字符串常量这样永远不能改变的东西是非常有用的。

管理 Toll-free转换
在许多Cocoa应用中,需要用到Core Foundation类型的对象。编译器不能自动管理Core Foundation对象,需要调用CFRetain和CFRelease类似的Core Foundation内存管理规则。
当你需要转换Objective C和Core Foundation对象时,需要使用cast函数或者Core Foundation的宏显示的告诉编译器你们之间的语义关系。

__bridge 转换Objective C和Core Foundation之间的指针,不转移拥有关系。
__bridge_retained 或者CFBridgingRetain转换一个Objective c指针到Core Foundation 指针并且转移拥有关系。你需要自己释放对象的关系。
__bridge_transfer 或者CFBridgingRelease将一个非Objective指针转换为Objective C的指针并且转移关系到ARC,不需要自己释放对象的关系
比如:以前的代码
- ( void )logFirstNameOfPerson:(ABRecordRef)person {
    
NSString  *name = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
    
NSLog ( @"Person's first name: %@" , name);
    [name 
release ];
}
在ARC中转化为以下代码。
- (
void )logFirstNameOfPerson:(ABRecordRef)person {
    
NSString  *name = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
    
NSLog ( @"Person's first name: %@" , name);
}

使用生命周期限定符来避免强引用循环
典型的是在父子继承层次中,父类需要引用了子类,子类同时也用到了父类,需要把父类中定义为strong,而子类中定义为weak。其他一些情况就比较难以琢磨,特别是调用了block对象。
在MRR中,__block id x 不增加x的引用计数,而在ARC中是增加引用计数的。为了在ARC中获得在MRR中同样的行为,需要使用__unsafe_unretain __block id x;但是这又是危险的且不鼓励的。更好的选择是使用__weak 或者设置把__block id的值设置为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,并且在block里面设置为nil
MyViewController  *  __block  myController = [[MyViewController alloc] init...];
myController.completionHandler =  ^(NSInteger result) {
    [myController dismissViewControllerAnimated:
YES  completion: nil ];
    myController = 
nil ;
};

同样可以定义一个临时的weak变量。
MyViewController *myController = [[MyViewController alloc] init...];
MyViewController *  __weak  weakMyViewController = myController;
myController.completionHandler =  ^(NSInteger result) {
    [weakMyViewController dismissViewControllerAnimated:
YES  completion: nil ];
};

对于特殊的引用循环,你需要这样使用。
MyViewController *myController = [[MyViewController alloc] init...];
MyViewController *  __weak  weakMyController = myController;
myController.completionHandler =  ^(NSInteger result) {
    MyViewController *strongMyController = weakMyController;
    
if  (strongMyController) {
        [strongMyController dismissViewControllerAnimated: YES  completion: nil ];
    }  else  {
    }
};
上述代码阐述了生命周期限定符的使用,需自己多揣摩。下一篇介绍以下Core Foundation内存管理,之后会介绍ios并发编程和线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值