总结一下:
将所有权从core foundation转移到object-c时,需要使用CFBridgingRelease().
将所有权从object-c转移到core foundation时,需要使用CFBridgingRetain().
当你想将一种类型临时当作另一种类型使用,而不转移所有权时,需要使用__bridge.
23. ARC中的内存泄露
环形持有一:timer--->view<----controller
timer<---view
1 2 1
当controller释放之后,controller的拥有者为0,执行其dealloc
环形持有一:timer--->view
timer<---view
1 1
在controller的dealloc里面调用 timer invalidate后,达到释放目的
环形持有一:timer--->view
timer<---view
0 0
如果一个自定义的view类,里面声明一个强指针的timer,那么timer和这个view类相互持有,这时,timer和view的拥有者都为1,如果你再把view添加到controller上面,那么view的拥有者为2,当controller执行dealloc后,view的拥有者由2减为1,这个时候不能只能在controller里面调用方法使view里面的定时器停止,打破循环持有的状态。
链状持有一:runloop---->timer---->view-------->源头得不到释放
1 1 1
如果你为了避免上述情况的产生,而对timer使用弱指针,那么情况可能更糟糕。虽然你的类不再拥有timer
但是timer仍然由另一个对象拥有,也就是run loop,所以,也就会导致我们使用的这个类一直被timer拥有,但.(括号中是我自己的理解,因为timer在ARC模式下有且仅有一个持有者,如果自己的类不持有timer,那么只能交给run loop了,但是,run loop持有timer的话,我们自己不能释放timer,自己的类可以释放timer,所以,timer一定要使用强指针)
环形持有二:controller--->customview--->block
1 1 1
如果在controller里面调用customview的block,且block里面直接调用self,self就是controller或者block捕获持有controller的变量,这样block间接地持有controller,下面的循环里只是多一个timer而已
环形持有二:controller--->customview--->block
<----block持有controller----
2 1 1
那么当controller被释放时,其拥有者由2减为1,其dealloc不执行
环形持有二:controller--->customview--->block
1 1 1
解决方法:一种方案是在 block 内部不要使用 self。,避免形成环状持有的状态,不让customview里面的block持有controller,也就是不能在block里面直接或间接地出现self,那意味着你不能 调用任何属性,实例变量,或者来自 block 的方法。局部变量可以。你不能使用实例变量的 原因是在场景后面会做 self-ivar 处理,因此仍然调用了 self。你使用待*的和id类型或者基本类型int BOOL等的实例变量时,xcode会给出形成循环持有的提示"Capturing 'self' strongly in this block is likely to lead to a retain cycle"
个人验证了一下,普通的block,比如一个controller类里的block不会出现这样的情况。
常用模型:
一、属性,局部变量,或者来自block的方法,都是用局部变量转换一下,完全避免self被调用,这个显然不太好
二、self局部化,如下所示,这样就可以随便使用属性了,因为self没有被block捕获而使得引用计数加一。但是,成员变量还是会形成,所有权循环,要么使用局部变量转换一下,要么都声明为属性,但是,前面文章提到如果不是外部借口需要使用,而仅仅是内存管理方面没有没有必要都使用属性。不过也可以成员变量在block使用时,用局部变量转换一下就OK了。
__weak SecondViewController * weakSelf = self;
m_view.m_block = ^ {
SecondViewController * strongSelf = weakSelf;
if (strongSelf != nil) {
NSLog(@"%@", strongSelf.m_testString);
}
};
只有像上面所示的block类型会出现问题,类自己内部的block不会出现此现象。block限定词最好是copy,strong有时候可能会崩溃。
在MRR模式下,上面类型的block这么写就OK了,任何以__block关键字为前缀的变量都不能被这个block保留引用计数。如果不加__block关键字,任何在block内部用到的指针变量,block都会copy一个只读复制的值,如果加了__block关键字,不复制值了,而且变量变为可读可写的了。
保持对象的活动状态
__block DelayedOperation *operation = [[DelayedOperation alloc] initWithDelay:5 block:^
{
NSLog( @"Performing operation" ); // do stuff
operation = nil ; }];
24.singleton
一帮情况下写法,但是如果你的单利用于多线程那么下面这个方法还不够健全。
+(id)sharedInstance
{
static NextViewController * controller = nil;
if (controller == nil) {
controller = [[NextViewController alloc] init];
}
return controller;
}
使用GCD库的dispatch_once()方法以确保对象的alloc,init确实只被执行一次,即使同一时刻多个线程去尝试执行这个block都没有问题。
+(id)sharedInstance
{
static NextViewController * controller = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
controller = [[NextViewController alloc] init];
});
return controller;
}
25.ARC模式下变量的默认初始化
ARC模式下,所有指针变量默认是nil,基本类型默认包含一些垃圾值,所以要赋具体的数值,否则会出现编译警告。这样使用一个没有指向一个有效对象的指针几乎不可能。
非ARC模式下,只有属性,成员变量的指针变量默认才是nil,局部指针变量不是nil,基本类型是随机数,而且会有编译警告,所以,要初始化为具体的值。
25.ARC中的内存泄露--转载网络
2,死循环
如果某个ViewController中有无限循环,也会导致即使ViewController对应的view关掉了,ViewController也不能被释放。
这种问题常发生于animation处理。
例,
比如,
CATransition *transition = [CATransition animation];
transition.duration = 0.5;
tansition.repeatCount = HUGE_VALL;
[self.view.layer addAnimation:transition forKey:"myAnimation"];
上例中,animation重复次数设成HUGE_VALL,一个很大的数值,基本上等于无限循环了。
解决办法是,在ViewController关掉的时候,停止这个animation。
-(void)viewWillDisappear:(BOOL)animated {
[self.view.layer removeAllAnimations];
}
26
值得注意的是,ARC并不能避免所有的内存泄露。使用ARC之后,工程中可能还会有内存泄露,不过引起这些内存泄露的主要原因是:block,retain循环,对CoreFoundation对象(通常是C结构)管理不善,以及真的是代码没写好。
(转自:http://www.devdiv.com/arc_-blog-312313-50692.html)