一、循環(huán)引用的幾種情況
自循環(huán)引用

image.png
a、b控制器
1. a強引用b
2. b有個屬性b1
3. a.b.b1 = a.b;
4. 當a釋放時 b無法正常釋放
相互循環(huán)引用

image.png
對象A內(nèi)部強持有obj,對象B內(nèi)部強持有obj,若此時對象A的obj指向?qū)ο驜,同時對象B中的obj指向?qū)ο驛,就是相互引用。
1.self強持有b
2.self.b.delegate = self;
3.b強引用delegate
4.self->b->delegate-->self
多循環(huán)引用

image.png
二、常見循環(huán)引用
1.block
對象強引用block,在block內(nèi)部又引用了該對象或者該對象的屬性就會造成循環(huán)引用
解決方法
1.weak-strong 強弱共舞
單獨使用weak會導(dǎo)致block持有的對象被提前釋放
__strong是為了防止block持有的對象提前釋放
__strong可以保證在block執(zhí)行完后改對象再釋放
__block 當前VC * vc = self ;
self.block = ^{
方法
self = nil ;
}
3.將self作為block的參數(shù)傳入
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
循環(huán)引用 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執(zhí)行dealloc前釋放timer
可以在viewWillAppear中創(chuàng)建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,這樣就不會引起循環(huán)引用,然后在dealloc方法中執(zhí)行NSTimer的銷毀,相對的FcTimer也會進行銷毀了。
3.使用系統(tǒng)提供的帶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的循環(huán)引用,使用__weak和__strong來避免
2.在持用NSTimer對象的類的方法中-(void)dealloc調(diào)用NSTimer 的- (void)invalidate方法;
4.使用基類NSProxy處理