一、循环引用的几种情况
自循环引用
image.png
a、b控制器
1. a强引用b
2. b有个属性b1
3. a.b.b1 = a.b;
4. 当a释放时 b无法正常释放
相互循环引用
image.png
对象A内部强持有obj,对象B内部强持有obj,若此时对象A的obj指向对象B,同时对象B中的obj指向对象A,就是相互引用。
1.self强持有b
2.self.b.delegate = self;
3.b强引用delegate
4.self->b->delegate-->self
多循环引用
image.png
二、常见循环引用
1.block
对象强引用block,在block内部又引用了该对象或者该对象的属性就会造成循环引用
解决方法
1.weak-strong 强弱共舞
单独使用weak会导致block持有的对象被提前释放
__strong是为了防止block持有的对象提前释放
__strong可以保证在block执行完后改对象再释放
__block 当前VC * vc = self ;
self.block = ^{
方法
self = nil ;
}
3.将self作为block的参数传入
self.testBlock = ^(UIViewController *vc) {
//使用vc
};
self.testBlock(self);
2.代理
1.self强持有b
2.self.b.delegate = self;
3.b强引用delegate
4.self->b->delegate-->self
解决方法
使用weak修饰delegate
特例CABasicAnimationDelegate使用strong修饰
NStimer
循环引用 myTimer无法释放
self强引用myTimer,mytimer的target又是self
self.myTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(doSomething) userInfo:nil repeats:YES];
- (void)dealloc {
[self.myTimer invalidate];
self.myTimer = nil;
}
解决方法
1.在ViewController执行dealloc前释放timer
可以在viewWillAppear中创建timer
可以在viewWillDisappear中销毁timer
2.封装FcTimer
.h
@interface FcTimer : NSTimer
//开启定时器
- (void)startTimer;
//暂停定时器
- (void)stopTimer;
@end
.m
@implementation FcTimer {
NSTimer *_timer;
}
- (void)stopTimer{
if (_timer == nil) {
return;
}
[_timer invalidate];
_timer = nil;
}
- (void)startTimer{
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(work) userInfo:nil repeats:YES];
}
- (void)work{
NSLog(@"正在计时中。。。。。。");
}
- (void)dealloc{
NSLog(@"%s",__func__);
[_timer invalidate];
_timer = nil;
}
@end
这个方式主要就是让FcTimer强引用NSTimer,NSTimer强引用FcTimer,避免让NSTimer强引用ViewController,这样就不会引起循环引用,然后在dealloc方法中执行NSTimer的销毁,相对的FcTimer也会进行销毁了。
3.使用系统提供的带block的timer方法
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:
(BOOL)repeats block:(void (^)(NSTimer *timer))block
API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:
(BOOL)repeats block:(void (^)(NSTimer *timer))block
API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
- (instancetype)initWithFireDate:(NSDate *)date interval:
(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block
API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
1.避免block的循环引用,使用__weak和__strong来避免
2.在持用NSTimer对象的类的方法中-(void)dealloc调用NSTimer 的- (void)invalidate方法;
4.使用基类NSProxy处理