昨天下午工做的时候碰见一个这样的需求,网络请求失败后把请求数据保存到本地,并自动重发3次,时间间隔是10秒,若是3次后还失败的话,下一次启动这个接口的时候,把新数据和保存在本地的数据都要发送,刚开始觉得没多少难度,不就是网络请求发送数据嘛,首先脑子里的第一反应就是用定时器,初始化定时器,而后触发相应的方法,设置请求的次数标志,超过3次中止定时器。事实却证实我尚未理解定时器......数组
因为是老接口,不能修改,由于产品已经上线,修改会涉及到太多业务,因此只能客户端想办法处理。这样致使的问题就是新数据不能和旧数据一块儿整合在一块儿发送,得分两次发送。好吧,那就上吧,我就信心满满的上了。网络
初始化定时器,遍历本地的数据,分别对应建立一个定时器使用下面的方法,加载到定时器数组oop
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
而后fire执行。OK,搞定。性能
bi..bi...bi...bi....bi.....bi......测试
擦,定时器全乱了,10s内定时器没啥问题,10s后因此定时器都交替进行。。。这不是坑爹么。。。。ui
吸了口气,喝了一杯水,扫了一眼定时器的代码,灵光一闪,会不会是fire用错了,初始化的时候不要当即执行,等初始化完毕的时候在从数组里面拿出定时器,请求成功或者失败三次后再拿出第二个定时器请求。哈哈哈哈哈哈,应该不会错了,就这么办。spa
bi....bi.....bi.....bi....bi........设计
我了个去,稍微好一点了,20秒内的数据是正常的,后面的定时器又交替进行。。。。泥煤呀,甘都得。。。不过已经有进步了,至少20秒是正确的吧,再改改代码应该就能够了,因此立马想一下定时器的执行流程,后来发现会不会是多个定时器和一个定时器的运行是有区别的?由于本身以前基本上都是建立一个定时器就能够了,fire、invalidate使用。没办法,上SOF看看吧。后来才知道原来这两个方法初始化的定时器即便不用fire也会对应的NSTimeInterval后执行,fire只是让他们当即执行,把启动的时间提早到当前,就像一个演唱会原本打算10分钟后开始的,如今由于主唱提早10分钟到了会场,看见粉丝这么热情,提早开始了。code
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
但是问题又来了,那既然这样没办法控制定时器的执行,我这个功能岂不是无法作了,有没有什么办法能够控制定时器么,想执行的时候就执行,不想执行的时候就丢掉它。。。。blog
查找资料的过程当中还发现了几个初始化定时器的方法:两个类方法,一个实例方法。
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo; + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo; - (id)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(id)ui repeats:(BOOL)rep;
这和上面的初始化方法有什么区别么,接着发现者两个类方法和实例方法是要手动添加到NSRunLoop代码执行的:
[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
哈哈哈,这不就是我想要的东东嘛(ˇˍˇ),yo yo check now!
修改定时器的方法,手动添加NSRunLoop执行,而后网络请求不变。。。。OK,搞定。。
bi..bi.....bi....bi......
无压力了。。。。测试一个for循环1000次,没发生什么错误。。。好吧,来个总结。
一直都习惯用最上面的两个方法初始化定时器,而后fire,而且fire的做用只是把定时器的时间提早了,这个是以前使用的时候没有去考虑的。。这种东东在一个定时器下面不会有什么问题,可是多个定时器的话基本上就悲剧。。不过在同一个地方使用多个定时器这样的设计方法我暂时也不知道合理不合理,可能也会有意想不到的的错误,好比内存暴涨,性能受影响之类的,这个暂时没有去考虑,若是你有更好的解决方法,能够交流交流。