那些年咱們踩過的坑-NSTimer

  昨天下午工做的時候碰見一個這樣的需求,網絡請求失敗後把請求數據保存到本地,並自動重發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的做用只是把定時器的時間提早了,這個是以前使用的時候沒有去考慮的。。這種東東在一個定時器下面不會有什麼問題,可是多個定時器的話基本上就悲劇。。不過在同一個地方使用多個定時器這樣的設計方法我暫時也不知道合理不合理,可能也會有意想不到的的錯誤,好比內存暴漲,性能受影響之類的,這個暫時沒有去考慮,若是你有更好的解決方法,能夠交流交流。

相關文章
相關標籤/搜索