淺談iOS13中使用KVC設(shè)置UITextField占位符崩潰的原因

眾所周知,在iOS13中使用KVC設(shè)置UITextField占位符會導(dǎo)致崩潰忧设,出于好奇刁标,今天我對崩潰原因進行了一番簡單探索,現(xiàn)將探索過程記錄如下:

[textfield setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];

上面這段代碼在iOS13之前一直工作良好址晕,更新到iOS13后莫名其妙就崩潰了膀懈,需要通過設(shè)置attributedPlaceholder屬性來代替。很多人覺得是iOS13對KVC的支持變?nèi)趿私骼矣X得不太可能启搂,應(yīng)該是蘋果爸爸偷偷把私有實例變量名(或?qū)傩悦┙o改了。廢話不多說刘陶,開始驗證胳赌,首先下載一個Xcode11,分別在iOS13和iOS12系統(tǒng)中運行以下代碼易核,通過runtime獲取并打印UITextField的所有屬性:

unsigned int count;
objc_property_t *ptr = class_copyPropertyList([textfield class], &count);
for (NSUInteger i = 0; i < count; i++) {
    NSLog(@"%s", property_getName(ptr[i]));
}
free(ptr);

運行結(jié)果顯示匈织,無論是在iOS12還是iOS13環(huán)境下,都沒有“placeholderLabel”相關(guān)的屬性牡直,所以_placeholderLabel不是UITextField的屬性缀匕。既然能用KVC訪問,不是屬性碰逸,就應(yīng)該是實例變量咯乡小,繼續(xù)驗證,我們通過runtime獲取并打印UITextField的所有實例變量:

unsigned int count2;
Ivar *ptr2 = class_copyIvarList([textfield class], &count2);
for (NSUInteger i = 0; i < count2; i++) {
    NSLog(@"%s", ivar_getName(ptr2[i]));
}
free(ptr2);

果然饵史,我們在萬花叢中如愿找到了_placeholderLabel满钟,遺憾的是,無論在iOS12還是iOS13環(huán)境下胳喷,UITextField都存在這個實例變量湃番。顯然,我一開始的推測被啪啪打臉了吭露。

image.png

一條路走不通吠撮,馬上調(diào)整思路,去找其他線索讲竿,不防先來仔細研究一下蘋果給的崩潰信息

image.png

結(jié)合崩潰堆棧和拋出的異常信息繼續(xù)分析泥兰,首先,崩潰是發(fā)生在-[UITextField valueForKey:]题禀,也就是說鞋诗,UITextField獲取_placeholderLabel時其實就已經(jīng)崩潰了;再來看異常信息迈嘹,“access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug”削彬,_placeholderLabel被禁止使用,這是一個應(yīng)用程序bug,不知道大家之前有沒有遇到這種異常吃警,我是從來沒遇到過糕篇,通常都是valueForUndefinedKey:異常。
接下來我們驗證一下蘋果是否修改了valueForKey:的邏輯酌心,我們找一個和_placeholderLabel同級別的實例變量_textContentView,同樣按照按照KVC方式去設(shè)置其背景色

[textfield setValue:[UIColor redColor] forKeyPath:@"_textContentView.backgroundColor"];

在iOS13環(huán)境下運行代碼挑豌,沒有崩潰安券,而且textfield背景色被修改成了紅色,說明這段代碼已經(jīng)生效了氓英。至此侯勉,valueForKey:也得以沉冤得雪,退出了背鍋群铝阐!
還有一種可能址貌,蘋果在通過valueForKey:獲取實例時,對值為“_placeholderLabel”的key作了特殊處理徘键,當發(fā)現(xiàn)key為“_placeholderLabel”時练对,拋出上文中提到的異常。怎么證明呢吹害,我們知道KVC獲取實例時螟凭,對下劃線并不敏感,我們可以去掉下劃線來試試它呀。

[textfield setValue:[UIColor redColor] forKeyPath:@"placeholderLabel.textColor"];

iOS13環(huán)境下運行B菽小!纵穿!巧了不是下隧!巧了不是!可以正常工作了谓媒。忙活半天淆院,總算找到原因了。天下武功出少林篙耗,天下iOS奇淫技巧出runtime迫筑,接下來,又輪到萬能的runtime上場啦宗弯,添加以下代碼脯燃,老代碼不用作任何修改,又可以天下太平了:

@implementation UITextField (KVC)

+ (void)load {
    Method origin = class_getInstanceMethod([self class], @selector(valueForKey:));
    Method swizzing = class_getInstanceMethod([self class], @selector(swizzing_valueForKey:));
    if (class_addMethod([self class], @selector(valueForKey:), method_getImplementation(swizzing), method_getTypeEncoding(swizzing))) {
        class_replaceMethod([self class], @selector(swizzing_valueForKey:), method_getImplementation(origin), method_getTypeEncoding(origin));
    }
    method_exchangeImplementations(origin, swizzing);
}

- (id)swizzing_valueForKey:(NSString *)key {
    if ([key isEqualToString:@"_placeholderLabel"]) {
        Ivar ivar = class_getInstanceVariable([self class], [key UTF8String]);
        id value = object_getIvar(self, ivar);

        return value;
    } else {
        return [self swizzing_valueForKey:key];
    }
}

當然蒙保,這段代碼主要是用來驗證猜想辕棚,不建議在開發(fā)中使用。蘋果的意圖很明顯,就是為了讓我們使用公開的attributedPlaceholder屬性來代替私有API逝嚎。

后記

這篇文章并沒有多少開發(fā)干貨扁瓢,主要是為了記錄一下自己探索的過程,希望能對今后定位同類型問題時提供一種思路补君。另外引几,文中如果有任何紕漏或錯誤,歡迎大家批評指正挽铁!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伟桅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子叽掘,更是在濱河造成了極大的恐慌楣铁,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件更扁,死亡現(xiàn)場離奇詭異盖腕,居然都是意外死亡,警方通過查閱死者的電腦和手機浓镜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進店門溃列,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人竖哩,你說我怎么就攤上這事哭廉。” “怎么了相叁?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵遵绰,是天一觀的道長。 經(jīng)常有香客問我增淹,道長椿访,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任虑润,我火速辦了婚禮成玫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拳喻。我一直安慰自己哭当,他們只是感情好,可當我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布冗澈。 她就那樣靜靜地躺著钦勘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪亚亲。 梳的紋絲不亂的頭發(fā)上彻采,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天腐缤,我揣著相機與錄音,去河邊找鬼肛响。 笑死岭粤,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的特笋。 我是一名探鬼主播剃浇,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼雹有!你這毒婦竟也來了偿渡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤霸奕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后吉拳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體质帅,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年留攒,在試婚紗的時候發(fā)現(xiàn)自己被綠了煤惩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡炼邀,死狀恐怖魄揉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拭宁,我是刑警寧澤洛退,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站杰标,受9級特大地震影響兵怯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腔剂,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一媒区、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧掸犬,春花似錦袜漩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至胜茧,卻和暖如春粘优,著一層夾襖步出監(jiān)牢的瞬間仇味,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工雹顺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留丹墨,地道東北人。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓嬉愧,卻偏偏與公主長得像贩挣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子没酣,可洞房花燭夜當晚...
    茶點故事閱讀 43,728評論 2 351

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

  • 前提 這段時間升級了 Xcode11.0王财,在 iOS13.0 運行的時候,當運行到 [textField setV...
    kwdx閱讀 4,048評論 5 20
  • KVC(Key-value coding)鍵值編碼裕便,單看這個名字可能不太好理解绒净。其實翻譯一下就很簡單了,就是指iO...
    我的夢工廠閱讀 891評論 1 8
  • KVC(Key-valuecoding)鍵值編碼偿衰,單看這個名字可能不太好理解挂疆。其實翻譯一下就很簡單了,就是指iOS...
    榕樹頭閱讀 702評論 0 2
  • 占位文字1下翎、曾經(jīng)有個這么一個項目需求: 使用textField時,占位文字默認是黑色的,我們的需求是當開始編輯時,...
    博行天下閱讀 884評論 2 1
  • KVC(Key-value coding)鍵值編碼缤言,iOS的開發(fā)中,可以允許開發(fā)者通過Key名直接訪問對象的屬性视事,...
    CALayer_Sai閱讀 2,517評論 0 4