昨天下午工作的时候遇见一个这样的需求,网络请求失败后把请求数据保存到本地,并自动重发3次,时间间隔是10秒,如果3次后还失败的话,下一次启动这个接口的时候,把新数据和保存在本地的数据都要发送,刚开始以为没多少难度,不就是网络请求发送数据嘛,首先脑子里的第一反应就是用定时器,初始化定时器,然后触发相应的方法,设置请求的次数标志,超过3次停止定时器。事实却证明我还没有理解定时器......

  由于是老接口,不能修改,因为产品已经上线,修改会涉及到太多业务,所以只能客户端想办法处理。这样导致的问题就是新数据不能和旧数据一起整合在一起发送,得分两次发送。好吧,那就上吧,我就信心满满的上了。

初始化定时器,遍历本地的数据,分别对应创建一个定时器使用下面的方法,加载到定时器数组

+ (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后所以定时器都交替进行。。。这不是坑爹么。。。。

  吸了口气,喝了一杯水,扫了一眼定时器的代码,灵光一闪,会不会是fire用错了,初始化的时候不要立即执行,等初始化完毕的时候在从数组里面拿出定时器,请求成功或者失败三次后再拿出第二个定时器请求。哈哈哈哈哈哈,应该不会错了,就这么办。

bi....bi.....bi.....bi....bi........

  我了个去,稍微好一点了,20秒内的数据是正常的,后面的定时器又交替进行。。。。泥煤呀,甘都得。。。不过已经有进步了,至少20秒是正确的吧,再改改代码应该就可以了,所以立马想一下定时器的执行流程,后来发现会不会是多个定时器和一个定时器的运行是有区别的?因为自己之前基本上都是创建一个定时器就可以了,fire、invalidate使用。没办法,上SOF看看吧。后来才知道原来这两个方法初始化的定时器即使不用fire也会对应的NSTimeInterval后执行,fire只是让他们立即执行,把启动的时间提前到当前,就像一个演唱会本来打算10分钟后开始的,现在因为主唱提前10分钟到了会场,看见粉丝这么热情,提前开始了。

+ (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;

  可是问题又来了,那既然这样没办法控制定时器的执行,我这个功能岂不是没法做了,有没有什么办法可以控制定时器么,想执行的时候就执行,不想执行的时候就丢掉它。。。。

  查找资料的过程中还发现了几个初始化定时器的方法:两个类方法,一个实例方法。

+ (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的作用只是把定时器的时间提前了,这个是之前使用的时候没有去考虑的。。这种东东在一个定时器下面不会有什么问题,但是多个定时器的话基本上就悲剧。。不过在同一个地方使用多个定时器这样的设计方法我暂时也不知道合理不合理,可能也会有意想不到的的错误,比如内存暴涨,性能受影响之类的,这个暂时没有去考虑,如果你有更好的解决方法,可以交流交流。

那些年我们踩过的坑-NSTimer的更多相关文章

  1. 那些年我们踩过的坑之表单reset

    开发者往往是在一个又一个的坑中成长起来的,自学的开发者尤其如此,刚刚填完一个坑,转身又掉进另一个坑.有些坑很容易就跳出来了,也有些坑能整了一天都没头绪,第二天早上一来发现后面就有一架通往坑外的梯子,坑 ...

  2. 那些年我们踩过的坑,SQL 中的空值陷阱!

    文章目录 NULL 即是空 三值逻辑 空值比较 NOT IN 与空值 函数与空值 DISTINCT.GROUP BY.UNION 与空值 ORDER BY 与空值 空值处理函数 字段约束与空值 SQL ...

  3. 项目中踩过的坑之-sessionStorage

    总想写点什么,却不知道从何写起,那就从项目中踩过的坑开始吧,希望能给可能碰到相同问题的小伙伴一点帮助. 项目情景: 有一个id,要求通过当前网页打开一个新页面(不是当前页面),并把id传给打开的新页面 ...

  4. web开发实战--弹出式富文本编辑器的实现思路和踩过的坑

    前言: 和弟弟合作, 一起整了个智慧屋的小web站点, 里面包含了很多经典的智力和推理题. 其实该站点从技术层面来分析的话, 也算一个信息发布站点. 因此在该网站的后台运营中, 富文本的编辑器显得尤为 ...

  5. "开发路上踩过的坑要一个个填起来————持续更新······(7月30日)"

    欢迎转载,请注明出处! https://gii16.github.io/learnmore/2016/07/29/problem.html 踩过的坑及解决方案记录在此篇博文中! 个人理解,如有偏颇,欢 ...

  6. 【转载】Fragment 全解析(1):那些年踩过的坑

    http://www.jianshu.com/p/d9143a92ad94 Fragment系列文章:1.Fragment全解析系列(一):那些年踩过的坑2.Fragment全解析系列(二):正确的使 ...

  7. Redis Cluster踩过的坑

    Redis Cluster踩过的坑请参考如下链接:http://www.iteye.com/blogs/subjects/Redis_Cluster_Devops

  8. 第八篇:web之前端踩的一些坑

    前端踩的一些坑   前端踩的一些坑 本节内容 事件代理 清除标签的所有事件 bootstrap的模态框自定义方法 ajax在django里面实现post提交 ajax提交数据嵌套 1.事件代理 之前写 ...

  9. 使用ffmpeg视频编码过程中踩的一个坑

           今天说说使用ffmpeg在写视频编码程序中踩的一个坑,这个坑让我花了好多时间,回头想想,非常多时候一旦思维定势真的挺难突破的.以下是不对的编码结果:                   ...

随机推荐

  1. 【bzoj4896】补退选

    傻逼题. 每个点维护下vector,然后随便做. #include<bits/stdc++.h> ; using namespace std; typedef long long ll; ...

  2. HDU 6119 小小粉丝度度熊 双指针

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6119 题意:中文题面. 解法:先处理可能交叉的区间,然后容易发现满足双指针的特性. //HDU 611 ...

  3. artdialog自定义多个按钮

    在实际运用到的过程中artdialog弹出框下面的按钮不止一个 可以自己定义多个按钮 function view_show(cust_id){$.dialog({        id: 'view_c ...

  4. HIbernate学习笔记4 之 延迟加载和 关联映射

    一.延迟加载 * 在使用hibernate一些方法的查询数据的时候,返回的只是一个空对象(除id外属性都为NULL),并没有真正的查询数据库,而是在使用这个对象时才会触发查询数据库,并将这些数据注入到 ...

  5. java获取项目路径,url路径

    我的web项目名iamgeModel. 工作空间在D盘 先获取url相关: 需要是HttpServletRequest request; 获取IP: request.getServerName() / ...

  6. 兼容python3的SSDB客户端

    SSDB.py import socket class SSDB_Response(object): def __init__(self, code='', data_or_message=None) ...

  7. AC日记——「SCOI2015」情报传递 LiBreOJ 2011

    #2011. 「SCOI2015」情报传递 思路: 可持久化树状数组模板: 代码: #include <bits/stdc++.h> using namespace std; #defin ...

  8. .net core 2.0学习记录(一):搭建一个.Net Core网站项目

    .Net Core开发可以使用Visual Studio 2017或者Visual Studio Code,下面使用Visual Studio 2017搭建一个.net Core MVC网站项目. 一 ...

  9. PTA L2-006 树的遍历-二叉树的后序遍历+中序遍历,输出层序遍历 团体程序设计天梯赛-练习集

    L2-006 树的遍历(25 分)   给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列.这里假设键值都是互不相等的正整数. 输入格式: 输入第一行给出一个正整数N(≤),是二叉树中结点的 ...

  10. 【IO】同步、异步、阻塞、非阻塞的理解

    最近一直在看跟IO模型有关的内容,感觉差不多理解了,于是开始写这一篇总结博客.针对的操作系统为UNIX/LINUX,大致的体系结构如上图. 操作系统中的客体主要包括了:文件,Socket和进程,本文主 ...