内容简介:在iOS中,调用通过
在iOS中, NSTimer
是我们平常都会用到的定时器。所以我们有必要了解其相关的使用方法和需要注意的点。在我们创建 NSTimer
定时器是 timer
是强引用 target
的这样就形成了循环引用的问题,从而导致内存泄漏。要避免这样的问题我们可以使用一下方法:
-
在合适的地方销毁NSTimer
在我们离开当前视图时,我们可以在
- (void)didMoveToParentViewController:(UIViewController *)parent
中销毁timer
- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"======== ViewController1 将要加载视图: viewDidLoad =======\n"); //iOS10 // self.timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) { // // }]; self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(changeTime) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode]; } - (void)changeTime { } - (void)didMoveToParentViewController:(UIViewController *)parent { if (!parent) { [self.timer invalidate]; self.timer = nil; } } - (void)dealloc { NSLog(@"======== ViewController1 释放: dealloc =======\n"); } 复制代码
-
使用
block
方式添加target-action
给NSTimer
分类添加方法如下:
+ (NSTimer *)S_timerWithTimeInterval:(NSTimeInterval)ti block:(void(^)(void))block userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo { return [self timerWithTimeInterval:ti target:self selector:@selector(blockSelector:) userInfo:[block copy] repeats:yesOrNo]; } + (void)blockSelector:(NSTimer *)timer { void(^block)(void) = timer.userInfo; if (block) { block(); } } 复制代码
调用
__weak typeof(self) weakSelf = self; self.timer = [NSTimer S_timerWithTimeInterval:1 block:^{ [weakSelf changeTime]; } userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode]; } - (void)changeTime { } 复制代码
通过 block
的方式将 action
传递出来,实际上timer的target是NSTimer类。即这样就不会产生循环引用。使用中由于使用了block所以要注意其引起的循环引用。
3. 定义中介继承NSProxy进行消息转发,消除强引用
关于NSProxy类的有关知识可以看链接的资料,这里就不再复述了。
@property (nonatomic, weak) id target; + (instancetype)proxyWithWeakTarget:(id)target; - (id)initWithTarget:(id)target; @end @implementation SProxy + (instancetype)proxyWithWeakTarget:(id)target { return [[SProxy alloc] initWithTarget:target]; } - (id)initWithTarget:(id)target { _target = target; return self; } ///将方法的签名(SEL)转发给真正实现了该消息的对象 - (void)forwardInvocation:(NSInvocation *)invocation { if ([_target respondsToSelector:invocation.selector]) { [invocation invokeWithTarget:_target]; } } ///为另一个类实现的消息创建一个有效的方法签名 - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { return [_target methodSignatureForSelector:sel]; } @end 复制代码
-
定义中介值继承自
NSObject
进行消息转发消除强引用
@interface TimerTraget : NSObject @property (nonatomic, weak) id target; + (instancetype)timerTragetWithTarget:(id)target; @end + (instancetype)timerTragetWithTarget:(id)target { TimerTraget *timer = [[TimerTraget alloc] init]; timer.target = target; return timer; } - (id)forwardingTargetForSelector:(SEL)aSelector { if ([self.target respondsToSelector:aSelector]) { return self.target; } return nil; } ///使用方法如下 self.timer = [NSTimer timerWithTimeInterval:1 target:[TimerTraget timerTragetWithTarget:self] selector:@selector(changeTime) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode]; } - (void)changeTime { } 复制代码
GCD定时器
在我们的平时开发中经常会用到定时器 ,相对于NSTimer实现的定时器,GCD定时器记录的时间相对要精确一些。而且不用考虑内存释放的问题。
以下是GCD实现基本的获取验证码的倒计时功能 直接上代码了
- (void)viewDidLoad { [super viewDidLoad]; self.but = [[UIButton alloc] initWithFrame:CGRectMake(self.view.center.x, self.view.center.y, 100, 50)]; // self.but.backgroundColor = [UIColor redColor]; [self.but setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal]; [self.but setTitle:@"获取验证码" forState:UIControlStateNormal]; self.but.titleLabel.font = [UIFont systemFontOfSize:15]; [self.but addTarget:self action:@selector(tapClick:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:self.but]; } - (void)tapClick:(UIButton*)but{ [self playGCDTimer]; } - (void)playGCDTimer{ __block NSInteger time = 59; //全局队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //创建timer 类型的定时器 (DISPATCH_SOURCE_TYPE_TIMER) dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); //设置定时器的各种属性(何时开始,间隔多久执行) // GCD 的时间参数一般为纳秒 (1 秒 = 10 的 9 次方 纳秒) // 指定定时器开始的时间和间隔的时间 dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC); //任务回调 dispatch_source_set_event_handler(timer, ^{ if (time <= 0) { dispatch_source_cancel(timer);//关闭定时器 dispatch_async(dispatch_get_main_queue(), ^{ [self.but setTitle:@"重新发送" forState:UIControlStateNormal]; self.but.userInteractionEnabled = YES; }); }else{ int seconds = time % 60; dispatch_sync(dispatch_get_main_queue(), ^{ [self.but setTitle:[NSString stringWithFormat:@"重新发送(%.2d)",seconds] forState:UIControlStateNormal]; self.but.userInteractionEnabled = NO;//验证码获取时禁止用户点击 }); } time--; }); // 开始定时器任务(定时器默认开始是暂停的,需要复位开启) dispatch_resume(timer); } 复制代码
好了GCD创建定时器的基本方法就介绍完了
以上所述就是小编给大家介绍的《iOS定时器相关实践》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 各种定时器--最全的定时器使用
- java定时器无法自动注入的问题解析(原来Spring定时器可以这样注入service)
- Golang定时器陷阱
- jmeter(七)定时器
- iOS定时器使用
- 设计一个简单准确的定时器
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。