昨天在做界面開發(fā)的時候阵赠,碰到一個修改 UISearchbBar
上的cancle
取消按鈕顏色的問題言沐,跳轉(zhuǎn)到UISearchBar
的頭文件看API說明隆箩,并未找到可以修改其屬性和方法响驴。
然后我使用Xcode上的 Debug View Hierarchy 工具來查看圖層秀存,發(fā)現(xiàn)原來顯示取消按鈕的是一個叫 UINavigationButton
類的對象:
UINavigationButtion
感覺既熟悉又陌生捶码,我在代碼里嘗試調(diào)用它,發(fā)現(xiàn)是個私有類或链,無法被獲取惫恼。于是我想到了 Runtime ,用class_copyIvarList
來獲取它所有的成員變量澳盐,通過遍歷找到想要的對象名稱祈纯,代碼如下:
unsigned int memberCount = 0;
Ivar *ivarList = class_copyIvarList([UISearchBar class], &memberCount);
for (unsigned int j=0; j<memberCount; j++) {
Ivar ivar = ivarList[j];
const char *name = ivar_getName(ivar);
const char *type = ivar_getTypeEncoding(ivar);
NSLog(@"-[name]:%s [type]:%s",name,type);
}
free(ivarList);
通過日志找到 cancle
相關(guān)的名稱:
找到了對應(yīng)對象的名稱,就可以通過KVC的 valueForKey
來獲取對象的實(shí)例并修改它的屬性叼耙,代碼如下:
UIButton *cancleNavBtn = [self.searchBar valueForKey:@"_cancelButton"];
[cancleNavBtn setTitle:@"取消" forState:UIControlStateNormal];
[cancleNavBtn setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal];
通過斷點(diǎn)我們可以發(fā)現(xiàn)其實(shí)這個 button 就是之前的UINavigationButton
腕窥。
上面解決的方式還不夠完美,我們再看日志下一行有個cancel相關(guān)的 UIBarButtonItem
筛婉,我推測UIBarButtonItem
應(yīng)該是UINavigationButtion
的子類簇爆。
既然是 UIBarButtonItem
就應(yīng)該可以用appearance
來修改全局的屬性,于是我推導(dǎo)出正確修改取消按鈕的方法:
[[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil]
setTitle:@"取消"];
NSDictionary *textDic = @{NSForegroundColorAttributeName:[UIColor blackColor]};
[[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil]
setTitleTextAttributes:textDic
forState:UIControlStateNormal];
-
上面應(yīng)該才是官方推薦的正確姿勢倾贰,但這些內(nèi)容并不是本篇文章的重點(diǎn)冕碟,我們回到剛才的
UINavigationButton
,這個私有button讓我聯(lián)想到幾年前讀的@我就叫Sunny怎么了的一篇文章從NSArray看類簇匆浙,內(nèi)容是關(guān)于類簇(Class Clusters)安寺,那么 UIButton 算不算是一種類簇呢? -
類簇(Class Clusters)是什么首尼?
類簇(Class Clusters) 是抽象工廠模式在iOS下的一種實(shí)現(xiàn)挑庶,在我們完全不知情的情況下,偷偷隱藏了很多具體的實(shí)現(xiàn)類软能,只暴露出簡單的接口迎捺。
用通俗一點(diǎn)講就是一個public
的抽象類加上一些private
的私有類構(gòu)成的,它是對一些實(shí)現(xiàn)細(xì)節(jié)進(jìn)行隱藏查排,而對外公開的行為進(jìn)行統(tǒng)一的一種設(shè)計(jì)凳枝。
例如我們常用的NSNumber
,NSArray
,NSDictionary
以及NSString
等都屬于類簇。
為了確定UIButton算不算是類簇跋核,我們可以通過LLDB命令來驗(yàn)證這一點(diǎn)岖瑰。
首先對UIButton的構(gòu)造函數(shù)buttonWithType:
進(jìn)行斷點(diǎn)得到其運(yùn)行地址,命令如下:
breakpoint set -F '+[UIButton buttonWithType:]'
再用地址來打印對應(yīng)的匯編代碼砂代,命令如下:
dis -a 0x0000000xxxxxxxxx//這里的內(nèi)存地址是隨機(jī)的蹋订,根據(jù)上面獲取的地址
然后我們會得到一大段匯編代碼:注意一下每一行最后有Button關(guān)鍵字的地方,會發(fā)現(xiàn)一些平時沒見過的私有Button刻伊,如UIPopoverButton
, UINavigationButton
, UITexturedButton
, _UIPlacardButton
露戒,_UIShortPlacardButton
以及UIRoundedRectButton
等椒功。
通過這些發(fā)現(xiàn)的private的私有類,那么我們就可以證明其實(shí)這里的UIButton是一個類簇智什。
總結(jié):
刨根問底一直都是我們程序員追求的目標(biāo)动漾,本文通過一次簡單的調(diào)試,意外發(fā)現(xiàn)UIButton也是類簇的一員撩鹿,并使用強(qiáng)大的LLDB讓我們了解到一些UIButton內(nèi)部構(gòu)造谦炬。遇到問題時悦屏,知其原理节沦,才能事半功倍。