在使用NSTimer或者CADisplayLink的的時候,如果我們把當前的控制器作為target傳入進入的話,那么他會在runloop中被持有,無法釋放。
self.timer = [NSTimer timerWithTimeInterval:1 target:pro selector:@selector(timeAction) userInfo:nil repeats:true];
這中問題最好的解決方案應該就是使用NSProxy,來打破循環(huán)引用。
- NSProxy是一個實現(xiàn)了NSObject協(xié)議的根類。
蘋果的官方文檔是這樣描述它的:
NSProxy 是一個抽象基類,它為一些表現(xiàn)的像是其它對象替身或者并不存在的對象定義API。一般的,發(fā)送給代理的消息被轉發(fā)給一個真實的對象或者代理本身引起加載(或者將本身轉換成)一個真實的對象。NSProxy的基類可以被用來透明的轉發(fā)消息或者耗費巨大的對象的lazy 初始化。
NSProxy實現(xiàn)了包括NSObject協(xié)議在內基類所需的基礎方法,但是作為一個抽象的基類并沒有提供初始化的方法。它接收到任何自己沒有定義的方法他都會產(chǎn)生一個異常,所以一個實際的子類必須提供一個初始化方法或者創(chuàng)建方法,并且重載forwardInvocation:方法和methodSignatureForSelector:方法來處理自己沒有實現(xiàn)的消息。一個子類的forwardInvocation:實現(xiàn)應該采取所有措施來處理invocation,比如轉發(fā)網(wǎng)絡消息,或者加載一個真實的對象,并把invocation轉發(fā)給他。methodSignatureForSelector:需要為給定消息提供參數(shù)類型信息,子類的實現(xiàn)應該有能力決定他應該轉發(fā)消息的參數(shù)類型,并構造相對應的NSMethodSignature對象。詳細信息可以查看NSDistantObject, NSInvocation, and NSMethodSignature的類型說明。
相信看了這些描述我們應該能對NSProxy有個初步印象,它僅僅是個轉發(fā)消息的場所,至于如何轉發(fā),取決于派生類到底如何實現(xiàn)的。比如我們可以在內部hold?。ɑ騽?chuàng)建)一個對象,然后把消息轉發(fā)給該對象。那我們就可以在轉發(fā)的過程中做些手腳了。甚至也可以不去創(chuàng)建這些對象,去做任何你想做的事情,但是必須要實現(xiàn)他的forwardInvocation:和methodSignatureForSelector:方法。
@implementation WXProxy
-(instancetype)initTarget:(id)target{
_target = target;
return self;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
NSLog(@"%s",__func__);
// return [NSObject instanceMethodSignatureForSelector:sel];
return [NSObject instanceMethodSignatureForSelector:@selector(init)];
}
- (id)forwardingTargetForSelector:(SEL)selector {
NSLog(@"%s",__func__);
return _target;
}
-(void)forwardInvocation:(NSInvocation *)invocation{
NSLog(@"%s",__func__);
// invocation.target = nil;
// [invocation invoke];
void *null = NULL;
[invocation setReturnValue:&null];
}
-(void)dealloc{
NSLog(@"%s",__FUNCTION__);
}
self.timer = [NSTimer timerWithTimeInterval:1 target:pro selector:@selector(timeAction) userInfo:nil repeats:true];