用runtime的關(guān)聯(lián)對象簡化你的UIAlertView

寫在前面

第一次寫博文,旨在分享在學(xué)習(xí)的過程中發(fā)現(xiàn)并解決問題的經(jīng)驗和一些看法。最近在學(xué)習(xí)runtime的相關(guān)知識,看到關(guān)聯(lián)對象這一點時,覺得挺有意思的。PS:這篇文章的點子來自《Effective Objective-C 2.0》。

關(guān)于UIAlertView

在iOS8以前,我們需要彈出一個AlertView并且自定義響應(yīng)的事件時候,都需要遵守<UIAlertViewDelegate>,然后在回調(diào)方法中根據(jù)索引去處理點擊之后的邏輯。

久而久之,真心覺得這是一個非常繁瑣而無趣的過程。并且,如果在一個頁面中,有多個alertView需要彈出的時候,那么你還需要對每一個判斷是哪個alertView。那么,有沒有什么好的辦法可以簡化這些繁瑣的過程呢?最好的方式就是傳入一個block作為事件的回調(diào)。iOS8已經(jīng)有了UIAlertController,并且可以通過給其添加UIAlertAction的方式來指定每個選項點擊事件。action也是采取了block的方式。

+ (instancetype)actionWithTitle:(NSString *)title style:(UIAlertActionStyle)style handler:(void (^)(UIAlertAction *action))handler;

我們也可以通過給UIView添加分類(Category)的方式來達到類似的效果。

UIVIew+MyAlertView

添加兩個方法(為了方便,可以自己選擇用哪種),并且定義響應(yīng)的block。

函數(shù)聲明

第一個方法中,為什么要把action放在那么尷尬的位置?因為alertView的變參(OtherButtonTitles,...)只能作為方法的最后一個參數(shù)。

我們來看兩個方法的實現(xiàn)。

方法一

這里有個小問題,就是我們自定義的方法,傳進來的other這個可變的參數(shù),在我們創(chuàng)建一個alertView的時候,只能取到第一個參數(shù)。什么意思呢?比如你在調(diào)用的時候傳入@"A",@"B",nil,如果你直接使用了這個參數(shù),那么你的alertView只能顯示"A"這個按鈕。具體的原因我找了好久也沒有找到(如果你知道,請告訴我,thank you)。所以我采用了遍歷這個變參,通過alertView自身的addButtonWithTitle:方法來添加按鈕。

有關(guān)可變參數(shù)的知識,可以參考wikipedia中的解釋

接下來的就是runtime中的關(guān)聯(lián)對象(associative)了。我們要在alertView的代理方法中,執(zhí)行block,所以我們需要把block保存起來(雖然可以用全局變量的來做)。但是我們知道,oc的分類(也叫類別)是無法擴展屬性的(I don't konw why)。那么我們則可用在運行時給他關(guān)聯(lián)上。

objc_setAssociatedObject(<#id object#>, <#const void *key#>, <#id value#>, <#objc_AssociationPolicy policy#>)

-- object是關(guān)聯(lián)到誰身上(self)。

-- void *key就是一個鍵,用來找到關(guān)聯(lián)的對象,和NSDictionary的key是一樣的,需要傳入一個void *指針。

-- value是要關(guān)聯(lián)的對象(這里是block)。

-- 最后一個是對這個對象(block)的內(nèi)存管理方針。取值和oc中的屬性修飾符是像對應(yīng)的,比如 OBJC_ASSOCIATION_COPY=> copy。

與之相對應(yīng)方法objc_getAssociatedObject(id object,void *key)則就是從字典中取值一般。

方法二除了更簡潔,總的來說于一無差。

方法二

我們在使用的時候呢,則會比較方便了,不必寫代理方法、不必判斷,而且代碼邏輯不必分散。

方法使用

細(xì)心的你可能已經(jīng)注意到了這種方式的隱患,就是block的保留循環(huán)(retain cycle)問題。

self通過關(guān)聯(lián)對象保留了action塊,如果在在action塊中引用了self的成員變量(假定為對象),比如說對這個對象賦值,那么action這個block則會通過這個成員變量間接又引用self,那么保留循環(huán)就產(chǎn)生了。

我們這個比較好解決,因為我們在點擊完了alertView之后,就不必在持有這個action塊了,所以在callBack執(zhí)行之后(見方法二圖),就把關(guān)聯(lián)的對象給remove掉了。為什么不用objc_removeAssociatedObjects?蘋果說這個方法的目的是為了讓被關(guān)聯(lián)者,回到最初的狀態(tài)。如果你僅僅需要remove某個關(guān)聯(lián)的對象,用set方法設(shè)置成nil就行了。

總的來說,關(guān)聯(lián)對象還是挺有意思的。擴展開來,比如說你要給任何的視圖添加tap手勢、滑動手勢等,都可以使用這種方式。不過需要注意的就是保留循環(huán)的問題。

歡迎各位指正糾錯,與君共勉。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,776評論 0 9
  • 繼上Runtime梳理(四) 通過前面的學(xué)習(xí),我們了解到Objective-C的動態(tài)特性:Objective-C不...
    小名一峰閱讀 770評論 0 3
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,638評論 33 466
  • ? 這兩天關(guān)于征不征房產(chǎn)稅的話題又死灰復(fù)燃,原因起于日前舉辦的2017博鰲房地產(chǎn)論壇現(xiàn)場,諸位經(jīng)濟學(xué)大咖激烈交鋒,...
    一笑雜談閱讀 773評論 6 14
  • 柑普茶是一種茶飲品,是柑的實體里面填滿普洱茶互相滲透發(fā)酵,兩者的融合沖出來的茶風(fēng)味獨特且有保健養(yǎng)生的效果,當(dāng)...
    mandychen1999閱讀 154評論 0 0