前言
NSTimer
是我們?nèi)粘i_發(fā)用的比較多的,但是由于我們在設(shè)置target
的時(shí)候通常都是傳的self
;系統(tǒng)在target
內(nèi)部會(huì)強(qiáng)引用當(dāng)前的self
,而一旦我們的NSTimer
設(shè)置為成員變量或者屬性的時(shí)候,那么timer
就是當(dāng)前self
所持有,所以就導(dǎo)致了互相引用。
解決方案
1、在viewWillDisappear
里面銷毀timer
(不推薦)
2、在didMoveToParentViewController
內(nèi)部釋放
3、引入中間類,并動(dòng)態(tài)添加方法
4、二次包裝NSTimer
5、使用NSTimer
的block
方法(iOS10
之后才能使用)
6、創(chuàng)建一個(gè)分類使用block
回調(diào)
7、用NSProxy
抽象類 (推薦使用)
一、在viewWillDisappear
里面銷毀timer
- 在
viewWillAppear
中創(chuàng)建timer
- 在
viewWillDisappear
中銷毀timer
二、在didMoveToParentViewController
內(nèi)部釋放
@property (nonatomic, strong) NSTimer *timer;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(__run) userInfo:nil repeats:YES];
- (void)didMoveToParentViewController:(UIViewController *)parent {
if (parent == nil) {
[self.timer invalidate];
self.timer = nil;
}
NSLog(@"-----release");
}
三、引入中間類,并動(dòng)態(tài)添加方法
導(dǎo)入頭文件#import <objc/runtime.h>
NSObject *obj = [[NSObject alloc] init];
Method method = class_getInstanceMethod(object_getClass(self), @selector(__run));
class_addMethod([obj class], @selector(__run), method_getImplementation(method), "v@:");
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:obj selector:@selector(__run) userInfo:nil repeats:YES];
四、二次包裝NSTimer
LGSafeTimer
代碼實(shí)現(xiàn)
@interface LGSafeTimer : NSObject
+ (LGSafeTimer *)lg_scheduledTimerWithTimeInterval:(NSTimeInterval)timerinterval
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats;
- (void)lg_inValidate;
@end
#import "LGSafeTimer.h"
@interface LGSafeTimer ()
@property (nonatomic, weak) id target;
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, assign) SEL selector;
@end
@implementation LGSafeTimer
+ (LGSafeTimer *)lg_scheduledTimerWithTimeInterval:(NSTimeInterval)timerinterval
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats {
LGSafeTimer *timer = [[LGSafeTimer alloc] scheduledTimerWithTimeInterval:timerinterval
target:aTarget
selector:aSelector
userInfo:userInfo
repeats:repeats];
return timer;
}
- (instancetype)scheduledTimerWithTimeInterval:(NSTimeInterval)timerinterval
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats {
if (self == [super init]) {
self.target = aTarget;
self.selector = aSelector;
self.timer = [NSTimer scheduledTimerWithTimeInterval:timerinterval
target:self
selector:@selector(lg_safeTimerRun)
userInfo:userInfo
repeats:repeats];
}
return self;
}
- (void)lg_inValidate {
[self.timer invalidate];
self.timer = nil;
}
- (void)dealloc {
NSLog(@"%@ --- %s", self, __func__);
}
#pragma mark - Private Methods
- (void)lg_safeTimerRun {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
if ([self.target respondsToSelector:self.selector]) {
[self.target performSelector:self.selector];
}
#pragma clang diagnostic pop
}
@end
使用:
在dealloc
函數(shù)內(nèi)部需要釋放timer
@property (nonatomic, strong) LGSafeTimer *safeTimer;
self.safeTimer = [LGSafeTimer lg_scheduledTimerWithTimeInterval:1 target:self selector:@selector(__run) userInfo:nil repeats:YES];
- (void)dealloc {
NSLog(@"--------%s------dealloc", __func__);
[self.safeTimer lg_inValidate];
}
五、創(chuàng)建一個(gè)分類使用block
回調(diào)
NSTimer+LGSafeTimer
實(shí)現(xiàn)
- 將定時(shí)器所執(zhí)行的任務(wù)封裝成
Block
,在調(diào)用定時(shí)器函數(shù)時(shí),把block
作為userInfo
參數(shù)傳進(jìn)去 - 計(jì)時(shí)器現(xiàn)在的
target
是NSTimer
類對象,這是個(gè)單例,因此計(jì)時(shí)器是否會(huì)保留它,其實(shí)都無所謂。此處依然有保留環(huán),然而因?yàn)轭悓ο螅╟lass object)無需回收,所以不用擔(dān)心
+ (NSTimer *)lg_scheduledTimerWithTimeInterval:(NSTimeInterval)timerinterval
repeats:(BOOL)repeats
block:(void (^)(void))block {
return [NSTimer scheduledTimerWithTimeInterval:timerinterval
target:self
selector:@selector(__fun:)
userInfo:[block copy]
repeats:repeats];
}
+ (void)__fun:(NSTimer *)timer {
void(^block)(void) = timer.userInfo;
if (block) {
block();
}
}
使用:
block
內(nèi)部注意循環(huán)引用
self.timer = [NSTimer lg_scheduledTimerWithTimeInterval:1 repeats:YES block:^{
NSLog(@"---------");
}];
六、使用NSTimer
的內(nèi)部API
- 10.0以后才能使用**
-
block
內(nèi)部注意循環(huán)引用**
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"---------");
}];
七、NSProxy
抽象類
LGProxy
代碼實(shí)現(xiàn)
@interface LGProxy : NSProxy
+ (instancetype)proxyWithObject:(id)object;
@end
#import "LGProxy.h"
@interface LGProxy ()
@property (nonatomic, weak) id object;
@end
@implementation LGProxy
+ (instancetype)proxyWithObject:(id)object {
LGProxy *proxy = [LGProxy alloc];
proxy.object = object;
return proxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
if (self.object) {
return [self.object methodSignatureForSelector:sel];
}
return nil;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
if ([self.object respondsToSelector:invocation.selector]) {
[invocation invokeWithTarget:self.object];
}
}
@end
使用:
LGProxy *proxy = [LGProxy proxyWithObject:self];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:proxy selector:@selector(__run) userInfo:nil repeats:YES];