runtime使用篇: object_getIvar、class_copyIvarList、ivar_getName、ivar_getTypeEncoding 和 class_getInstanceVariable

前言:
  • 本篇文章將介紹以下幾個和實(shí)例變量ivar相關(guān)的runtime函數(shù)的使用
    id object_getIvar(id obj, Ivar ivar)
    Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
    const char *ivar_getName(Ivar v)
    const char *ivar_getTypeEncoding(Ivar v)
    Ivar class_getInstanceVariable(Class cls, const char *name)
1. id object_getIvar(id obj, Ivar ivar)

分析: Ivar,即InstanceVariable(實(shí)例變量)。runtime對該函數(shù)的說明為:
Reads the value of an instance variable in an object.
即獲取一個對象obj的實(shí)例變量ivar的值。要使用這個函數(shù),首先需要一個Ivar,我們使用class_copyIvarList函數(shù)獲取一個Ivar數(shù)組從而獲取一個Ivar,現(xiàn)在先看看class_copyIvarList函數(shù)是怎么使用的

2. Ivar *class_copyIvarList(Class cls, unsigned int *outCount)

說明:該函數(shù)的作用是獲取傳入類的所有實(shí)例變量,返回的是實(shí)例變量數(shù)組
UITextField類為例,代碼示例如下:

unsigned int outCount;
Ivar *ivars = class_copyIvarList([UITextField class], &outCount);

for (int i = 0; i < outCount; i++) {
    Ivar ivar = ivars[i];
}

free(ivars);

說明:由于ARC只適用于Foundation等框架,對于Core Foundationruntime 等并不適用,所以在使用帶有copy、retain等字樣的函數(shù)或方法時需要手動釋放free()
獲取到Ivar后可以利用 ivar_getName 函數(shù)獲取 Ivar 的名稱,用 ivar_getTypeEncoding 函數(shù)獲取 Ivar 的類型編碼,通過類型編碼就可以知道該 Ivar 是何種類型的。
關(guān)于類型編碼,這里稍微說一點(diǎn):

為了協(xié)助runtime系統(tǒng),編譯器用字符串為每個方法的返回值和參數(shù)的類型進(jìn)行了編碼,并把該編碼和方法選擇器進(jìn)行綁定。這種編碼方案在其他上下文環(huán)境中也是有用的,因此它可以使用編譯器指令@encode()進(jìn)行獲取。當(dāng)給定一種類型時,@encode()就會返回對這種類型進(jìn)行編碼后的字符串,類型可以是基本類型比如int、指針、結(jié)構(gòu)、并集、類的名稱等等,事實(shí)上,它們也都可以作為C語言sizeof()運(yùn)算符的參數(shù)。(每種基本類型和編碼的對應(yīng)關(guān)系詳見蘋果官方文檔以及這篇譯文

整體代碼如下:

unsigned int outCount; // 1
Ivar *ivars = class_copyIvarList([UITextField class], &outCount); // 2

for (int i = 0; i < outCount; i++) { // 3
    Ivar ivar = ivars[i]; // 4
    const char *ivarName = ivar_getName(ivar); // 5
    const char *ivarType = ivar_getTypeEncoding(ivar); // 6
    NSLog(@"實(shí)例變量名為:%s 字符串類型為:%s", ivarName, ivarType); // 7
} // 8
free(ivars); // 9

打印結(jié)果如下:

runtime[6630:406123] 實(shí)例變量名為:_textStorage 字符串類型為:@"_UICascadingTextStorage"
runtime[6630:406123] 實(shí)例變量名為:_borderStyle 字符串類型為:q
runtime[6630:406123] 實(shí)例變量名為:_minimumFontSize 字符串類型為:d
runtime[6630:406123] 實(shí)例變量名為:_delegate 字符串類型為:@
runtime[6630:406123] 實(shí)例變量名為:_background 字符串類型為:@"UIImage"
runtime[6630:406123] 實(shí)例變量名為:_disabledBackground 字符串類型為:@"UIImage"
runtime[6630:406123] 實(shí)例變量名為:_clearButtonMode 字符串類型為:q
runtime[6630:406123] 實(shí)例變量名為:_leftView 字符串類型為:@"UIView"
runtime[6630:406123] 實(shí)例變量名為:_leftViewMode 字符串類型為:q
runtime[6630:406123] 實(shí)例變量名為:_rightView 字符串類型為:@"UIView"
// 省略大部分
runtime[6630:406123] 實(shí)例變量名為:_placeholderLabel 字符串類型為:@"UITextFieldLabel"
runtime[6630:406123] 實(shí)例變量名為:_suffixLabel 字符串類型為:@"UITextFieldLabel"
// 省略大部分

現(xiàn)在就獲取到了UITextField類的所有實(shí)例變量,包括私有的。

使用場景:

有了這些實(shí)例變量就可以更方便地更改UITextField了,比如更改UITextField的占位字體顏色,占位字體默認(rèn)的顏色偏向于亮灰色,如下圖:

默認(rèn)的占位字體.png

由于UITextField沒有提供直接修改占位字體顏色的屬性,現(xiàn)在我們用其他方法嘗試。從剛才打印的實(shí)例變量名稱可以推測實(shí)例變量_placeholderLabel是顯示占位字體的一個UILabel,現(xiàn)在驗(yàn)證一下,在剛才代碼的第9行后添加如下代碼:

// self.textField就是上圖顯示的UITextField
id value = [self.textField valueForKey:@"_placeholderLabel"]; // 10
NSLog(@"value class:%@, value superclass:%@", NSStringFromClass([value class]), NSStringFromClass([value superclass])); // 11

打印結(jié)果如下:

runtime[44760:4568971] value class:UITextFieldLabel, value superclass:UILabel

可以看到,實(shí)例變量_placeholderLabel的類和剛才用類型編碼獲取到的相同。
既然實(shí)例變量_placeholderLabelUILabel子類的實(shí)例,那就可以根據(jù)UILabeltextColor屬性利用KVCUITextField更改字體顏色了:

[self.textField setValue:[UIColor orangeColor] forKeyPath:@"_placeholderLabel.textColor"]; // 12

重新進(jìn)行后效果如下圖:

修改后的占位字體.png
3. Ivar class_getInstanceVariable(Class cls, const char *name)

此時再回到第一個函數(shù)id object_getIvar(id obj, Ivar ivar)的使用方法,有了Ivar名稱后如果需要再用到該Ivar,就需要用到class_getInstanceVariable函數(shù),該函數(shù)是的作用是獲取指定類的指定名稱的實(shí)例變量。現(xiàn)在在剛才的代碼后添加如下代碼:

Ivar ivar = class_getInstanceVariable([UITextField class], "_placeholderLabel");
id getIvar = object_getIvar(self.textField, ivar);
NSLog(@"%@", getIvar);

打印結(jié)果如下:

runtime[45217:4596711] <UITextFieldLabel: 0x7fe6e35e6ad0; frame = (0 0; 0 0); text = 'please input text'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fe6e35e69d0>>

得到的即是對象self.textField的ivar名稱為_placeholderLabel的值。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 對于從事 iOS 開發(fā)人員來說,所有的人都會答出【runtime 是運(yùn)行時】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,799評論 7 64
  • 原文出處:南峰子的技術(shù)博客 Objective-C語言是一門動態(tài)語言,它將很多靜態(tài)語言在編譯和鏈接時期做的事放到了...
    _燴面_閱讀 1,404評論 1 5
  • Objective-C語言是一門動態(tài)語言,他將很多靜態(tài)語言在編譯和鏈接時期做的事情放到了運(yùn)行時來處理。這種動態(tài)語言...
    tigger丨閱讀 1,573評論 0 8
  • 我們常常會聽說 Objective-C 是一門動態(tài)語言,那么這個「動態(tài)」表現(xiàn)在哪呢?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,319評論 0 7
  • 故事背景:為了讓物理像素密度更高的iphone6s等手機(jī)享受高清圖片定制(同時普通手機(jī)對圖片的質(zhì)量可以降低),我們...
    stois閱讀 2,040評論 2 0

友情鏈接更多精彩內(nèi)容