[iOS]1行代碼快速集成按鈕延時處理(實戰)

1. 按鈕延時處理事件有什么應用場景?

如果你做的是一個帶有輕微社交功能的APP,這類APP一般都會有類似“收藏”、“點贊”、“喜愛”的功能。

這些功能其實載體是一個UIButton,如果你在每次用戶點贊的時候都發請求給服務器,假如有些用戶“手便宜”,在那里重復的點擊,就會造成一個請求還沒回來,有連續發送出去好幾個請求。

出現這種情況,第一,可能造成服務器不必要的壓力,這簡直是必然的;第二,由于你不確定請求回調什么時候回來,假如用戶把這個控制器銷毀了,你的應用就可能奔潰。

這個場景就可以采用按鈕延時處理事件來輕松應對。

2.實例分析?

像下面的demo里寫的這樣:

JPBtnClickDelay

收藏這類功能的事件鏈是:用戶點擊-->處理點擊 -->發送請求

正常情況,用戶點擊按鈕,響應用戶點擊, 發送請求。

當使用延時處理以后(我這里設定延時時長為1.0Second),當用戶點擊按鈕以后,響應用戶點擊,但是不是立即發送請求,而是先檢查一下兩次點擊之間時間差有沒有1秒,如果有,再發送請求,如果沒有,不發送請求。

3、動態添加方法和屬性(hook)?

3.1 runtime是什么?

runtime簡稱運行時。OC就是運行時機制,也就是在運行時候的一些機制,其中最主要的是消息機制。

Objective-C 的 Runtime 是一個運行時庫(Runtime Library),它是一個主要使用 C 和匯編寫的庫,為 C 添加了面相對象的能力并創造了 Objective-C。這就是說它在類信息(Class information) 中被加載,完成所有的方法分發,方法轉發,等等。Objective-C runtime 創建了所有需要的結構體,讓 Objective-C 的面相對象編程變為可能。

3.2 動態添加方法和屬性是什么?

比如說,我要給一個人動態添加一個“吹牛逼”的屬性,方法是這樣的。先給人添加一個分類(Category),然后在分類里添加一個屬性。

注意,分類是專門用來添加方法的,在分類里使用關鍵字@property添加屬性,系統是不會幫我們生成setter-getter方法的。

所以我們要自己實現setter-getter方法。

在setter方法里使用runtime的以下方法動態添加屬性。

voidobjc_setAssociatedObject(idobject,constvoid*key,idvalue, objc_AssociationPolicy policy)

在getter方法里使用runtime的以下方法動態獲取屬性值。

idobjc_getAssociatedObject(idobject,constvoid*key)

3.3 方法交換是什么?

記得我們的每一個OC對象都有一個isa指針嗎?這個isa就是指向創建實例對象的類。

對象方法保存到類里面,每個類里面都有一個方法列表。

當調用對象方法的時候,系統都會來到這個表里查找對應的方法和實現。

方法映射表.png

所謂的方法交換,也就是hook,就是把兩個方法的實現給交換了。就像下面這張圖一,你調用eat方法的時候,就會去找run方法的實現。

hook.png

4.思路分析?

我們知道UIButton繼承自UIControl,UIButton的所有處理事件的能力都是它的父類UIControl傳給它的。UIControl有這樣一個方法:

// send the action. the first method is called for the event and is a point at which you can observe or override behavior. it is called repeately by the second.- (void)sendAction:(SEL)action to:(nullableid)target forEvent:(nullableUIEvent*)event;

官方的解釋翻譯過來是這樣的:這個方法用以傳遞事件消息,是監聽到事件后最先調用的方法,并且它是隨著事件的重復產生而頻繁調用的。

所以我們要實現攔截事件傳遞,重寫這個方法是最優解。

5.代碼實現?

首先為UIControl添加創建分類,并且在.h文件里添加屬性。

#import@interfaceUIControl(JPBtnClickDelay)/** 延遲時間 */@property(nonatomic)NSTimeIntervaljp_acceptEventInterval;@end

接下來來到.m文件

#import"UIControl+JPBtnClickDelay.h"#import@interfaceUIControl()/** 是否忽略點擊 */@property(nonatomic)BOOLjp_ignoreEvent;@end@implementationUIControl(JPBtnClickDelay)-(void)jp_sendAction:(SEL)action to:(id)target forEvent:(UIEvent*)event{if(self.jp_ignoreEvent)return;if(self.jp_acceptEventInterval>0) {self.jp_ignoreEvent=YES;? ? [selfperformSelector:@selector(setJp_ignoreEvent:) withObject:@(NO) afterDelay:self.jp_acceptEventInterval];}? ? [selfjp_sendAction:action to:target forEvent:event];}-(void)setJp_ignoreEvent:(BOOL)jp_ignoreEvent{? ? objc_setAssociatedObject(self,@selector(jp_ignoreEvent), @(jp_ignoreEvent), OBJC_ASSOCIATION_ASSIGN);}-(BOOL)jp_ignoreEvent{return[objc_getAssociatedObject(self, _cmd, boolValue];}-(void)setJp_acceptEventInterval:(NSTimeInterval)jp_acceptEventInterval{? ? objc_setAssociatedObject(self,@selector(jp_acceptEventInterval), @(jp_acceptEventInterval), OBJC_ASSOCIATION_ASSIGN);}-(NSTimeInterval)jp_acceptEventInterval{return[objc_getAssociatedObject(self, _cmd) doubleValue];}+(void)load{? ? Method sys_Method = class_getInstanceMethod(self,@selector(sendAction:to:forEvent:));? ? Method add_Method = class_getInstanceMethod(self,@selector(jp_sendAction:to:forEvent:));? ? method_exchangeImplementations(sys_Method, add_Method);}@end

6. 分類的使用?

這里有兩個UIButton的實例對象:

[self.normalBtnaddTarget:selfaction:@selector(normalBtnClick) forControlEvents:UIControlEventTouchUpInside];[self.delayBtnaddTarget:selfaction:@selector(delayBtnClick) forControlEvents:UIControlEventTouchUpInside];self.delayBtn.jp_acceptEventInterval=1.0f;

normalBtn不需要有延時,就什么也不用管,就和使用系統原生的一樣。

delayBtn需要延時,給它的jp_acceptEventInterval設定一個延時值,它自動就會生效。

7. Demo下載?

請點擊這里去往Github。


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容

  • 轉至元數據結尾創建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數據起始第一章:isa和Class一....
    40c0490e5268閱讀 1,755評論 0 9
  • Swift2.0 1.defer譯為延緩、推遲之意類似棧 注意作用域,其次是調用順序——即一個作用域結束(注意),...
    zeqinjie閱讀 3,394評論 0 50
  • 本文轉載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 772評論 0 1
  • 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,580評論 33 466
  • LG平日里一副溫情脈脈的暖男形象——我在微博《我和大熊的故事》里時時更新,已經寫到260多——遇到某些事情卻容易發...
    彼小清閱讀 554評論 4 2