場(chǎng)景: 使用NSTimer會(huì)產(chǎn)生循環(huán)引用, 所以, 當(dāng)對(duì)象應(yīng)該被銷(xiāo)毀的時(shí)候, 需要首先手動(dòng)移除NSTimer, 這樣, 該對(duì)象才對(duì)被銷(xiāo)毀. 手動(dòng)設(shè)置timer = nil.
timer之所以不能自動(dòng)像其他對(duì)象跟隨對(duì)象釋放而釋放
解決方案: 不讓定時(shí)器強(qiáng)引用對(duì)象.
問(wèn)題出在這里, 把target設(shè)置成self, 出現(xiàn)了循環(huán)引用. 如果target不設(shè)置成self, 就不會(huì)出現(xiàn)循環(huán)引用了.
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTest) userInfo:nil repeats:YES];
創(chuàng)建另外一個(gè)對(duì)象作為定時(shí)間消息的接受者, 但是不實(shí)現(xiàn)@selector(timerTest), 然后通過(guò)消息轉(zhuǎn)發(fā), 再發(fā)消息轉(zhuǎn)發(fā)到當(dāng)前對(duì)象中執(zhí)行.
@interface ProxyObj : NSObject
+ (instancetype)proxyWithTarget:(id)target;
@property (weak, nonatomic) id target;
@end
@implementation ProxyObj
+ (instancetype)proxyWithTarget:(id)target
{
MJProxyObj *proxy = [[MJProxyObj alloc] init];
proxy.target = target;
return proxy;
}
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return self.target;
}
@end
- (id)forwardingTargetForSelector:(SEL)aSelector 因?yàn)镻roxyObj最為定時(shí)器消息的接受者, 但是這個(gè)接受者并未實(shí)現(xiàn)定時(shí)器需要執(zhí)行的方法, 所以會(huì)執(zhí)行消息轉(zhuǎn)發(fā), 把這個(gè)消息轉(zhuǎn)發(fā)到能夠處理該消息的對(duì)象里, 很明顯, 能夠處理消息的就是ProxyObj.target
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[ProxyObj proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];
}
- (void)timerTest
{
NSLog(@"%s", __func__);
}
- (void)dealloc
{
NSLog(@"%s", __func__);
[self.timer invalidate];
}
@end
這樣就可以辦到timer不引用當(dāng)前對(duì)象, 不會(huì)造成循環(huán)引用. 也不用擔(dān)心timer何時(shí)釋放了.
優(yōu)化方法查找流程
繼承自NSObject的進(jìn)行消息轉(zhuǎn)發(fā)會(huì)先從方法緩存列表中找, 找不到再找當(dāng)前類(lèi)對(duì)象的方法列表中找, 找不到, 再依次往父類(lèi)中找, 最終找到NSObject的類(lèi)對(duì)象,
依然找不到, 然后拋出動(dòng)態(tài)方法解析, 動(dòng)態(tài)方法解析沒(méi)有實(shí)現(xiàn), 再拋出消息轉(zhuǎn)發(fā), 此時(shí)才會(huì)真正去調(diào)用到定時(shí)器的方法
按照目前的流程, 必定是需要消息轉(zhuǎn)發(fā)的, 但是還是先進(jìn)行一番的方法查找, 最后才進(jìn)行轉(zhuǎn)發(fā), 但是我們已經(jīng)很清楚的知道, 根本不需要進(jìn)行查找, 直接進(jìn)行轉(zhuǎn)發(fā)即可.
NSProxy: 專(zhuān)門(mén)做消息轉(zhuǎn)發(fā)的, 只要調(diào)用到NSProxy里面的方法, 就會(huì)立即執(zhí)行轉(zhuǎn)發(fā)
@interface Proxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@property (weak, nonatomic) id target;
@end
@implementation Proxy
+ (instancetype)proxyWithTarget:(id)target
{
// NSProxy對(duì)象不需要調(diào)用init,因?yàn)樗緛?lái)就沒(méi)有init方法
MJProxy *proxy = [MJProxy alloc];
proxy.target = target;
return proxy;
}
// NSProxy 是專(zhuān)門(mén)做消息轉(zhuǎn)發(fā)的, 只要調(diào)用到NSProxy里面的方法, 就會(huì)立即執(zhí)行下面的函數(shù)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
[invocation invokeWithTarget:self.target];
}
@end