分類(lèi)為什么不能添加成員變量

Property是屬性y,Ivar是成員變量

其實(shí)分類(lèi)中是可以為一個(gè)類(lèi)添加屬性的并巍,但是一定做不到添加成員變量目木,不要混淆了成員變量和屬性的概念

在一個(gè)分類(lèi)中添加了一個(gè)屬性,Xcode不會(huì)自動(dòng)的為其生成一個(gè)下劃線開(kāi)頭的成員變量及set和get方法懊渡,如果你沒(méi)有手動(dòng)的實(shí)現(xiàn)這兩個(gè)方法刽射,直接在外面通過(guò)點(diǎn)語(yǔ)法調(diào)用這個(gè)屬性,肯定就直接掛了剃执,Unrecognised selector send to instance誓禁,因?yàn)樗麎焊蜎](méi)有這兩個(gè)方法,所以當(dāng)你真的在分類(lèi)中聲明了一個(gè)屬性的時(shí)候肾档,就要手動(dòng)的去實(shí)現(xiàn)這個(gè)屬性的set和get方法摹恰,這個(gè)時(shí)候就要用到運(yùn)行時(shí)機(jī)制了辫继,關(guān)聯(lián)上去這個(gè)屬性的存取過(guò)程。

那么為什么不能給分類(lèi)添加成員變量呢

成員變量是一個(gè)類(lèi)的東西俗慈,分類(lèi)本身就不是一個(gè)類(lèi)姑宽,分類(lèi)本來(lái)就是OC里面通過(guò)運(yùn)行時(shí)動(dòng)態(tài)的為一個(gè)類(lèi)添加的一些方法和屬性等,不是一個(gè)真正的類(lèi)闺阱,你怎么給他添加成員變量呢炮车?

分類(lèi)里面不能添加Ivar是因?yàn)榉诸?lèi)本身并不是一個(gè)真正的類(lèi),它并沒(méi)有自己的ISA酣溃。類(lèi)最開(kāi)始生成了很多基本屬性瘦穆,比如IvarList,MethodList赊豌,分類(lèi)只會(huì)將自己的method attach到主類(lèi)扛或,并不會(huì)影響到主類(lèi)的IvarList。這就是為什么分類(lèi)里面不能增加成員變量的原因亿絮。



為什么不能添加成員變量呢告喊?

Objective-C類(lèi)是由Class類(lèi)型來(lái)表示的麸拄,它實(shí)際上是一個(gè)指向objc_class結(jié)構(gòu)體的指針派昧。它的定義如下:

typedef struct objc_class *Class;

objc_class結(jié)構(gòu)體的定義如下:

structobjc_class{Class isa? OBJC_ISA_AVAILABILITY;#if!__OBJC2__Class super_class? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;// 父類(lèi)constchar*name? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;// 類(lèi)名longversion? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;// 類(lèi)的版本信息,默認(rèn)為0longinfo? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;// 類(lèi)信息拢切,供運(yùn)行期使用的一些位標(biāo)識(shí)longinstance_size? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;// 該類(lèi)的實(shí)例變量大小structobjc_ivar_list*ivarsOBJC2_UNAVAILABLE;// 該類(lèi)的成員變量鏈表structobjc_method_list**methodListsOBJC2_UNAVAILABLE;// 方法定義的鏈表structobjc_cache*cacheOBJC2_UNAVAILABLE;// 方法緩存structobjc_protocol_list*protocolsOBJC2_UNAVAILABLE;// 協(xié)議鏈表#endif} OBJC2_UNAVAILABLE;

在上面的objc_class結(jié)構(gòu)體中蒂萎,ivars是objc_ivar_list(成員變量列表)指針;methodLists是指向objc_method_list指針的指針淮椰。在Runtime中五慈,objc_class結(jié)構(gòu)體大小是固定的,不可能往這個(gè)結(jié)構(gòu)體中添加數(shù)據(jù)主穗,只能修改泻拦。所以ivars指向的是一個(gè)固定區(qū)域,只能修改成員變量值忽媒,不能增加成員變量個(gè)數(shù)争拐。methodList是一個(gè)二維數(shù)組,所以可以修改*methodLists的值來(lái)增加成員方法晦雨,雖沒(méi)辦法擴(kuò)展methodLists指向的內(nèi)存區(qū)域架曹,卻可以改變這個(gè)內(nèi)存區(qū)域的值(存儲(chǔ)的是指針)。因此闹瞧,可以動(dòng)態(tài)添加方法绑雄,不能添加成員變量。

在Objective-C提供的runtime函數(shù)中奥邮,確實(shí)有一個(gè)class_addIvar()函數(shù)用于給類(lèi)添加成員變量万牺,但是文檔中特別說(shuō)明:

This function may only be called after objc_allocateClassPair and before objc_registerClassPair. Adding an instance variable to an existing class is not supported.

意思是說(shuō)罗珍,這個(gè)函數(shù)只能在“構(gòu)建一個(gè)類(lèi)的過(guò)程中”調(diào)用。一旦完成類(lèi)定義杏愤,就不能再添加成員變量了靡砌。經(jīng)過(guò)編譯的類(lèi)在程序啟動(dòng)后就runtime加載,沒(méi)有機(jī)會(huì)調(diào)用addIvar珊楼。程序在運(yùn)行時(shí)動(dòng)態(tài)構(gòu)建的類(lèi)需要在調(diào)用objc_allocateClassPair之后通殃,objc_registerClassPair之前才可以被使用,同樣沒(méi)有機(jī)會(huì)再添加成員變量厕宗。

Category不能添加成員變量(instance variables)画舌,那到底能不能添加屬性(property)呢?

這個(gè)我們要從Category的結(jié)構(gòu)體開(kāi)始分析:

typedefstructcategory_t{constchar*name;//類(lèi)的名字classref_tcls;//類(lèi)structmethod_list_t*instanceMethods;//category中所有給類(lèi)添加的實(shí)例方法的列表structmethod_list_t*classMethods;//category中所有添加的類(lèi)方法的列表structprotocol_list_t*protocols;//category實(shí)現(xiàn)的所有協(xié)議的列表structproperty_list_t*instanceProperties;//category中添加的所有屬性}category_t;

從Category的定義也可以看出Category的可為(可以添加實(shí)例方法已慢,類(lèi)方法曲聂,甚至可以實(shí)現(xiàn)協(xié)議,添加屬性)和不可為(無(wú)法添加實(shí)例變量)佑惠。

那我們?yōu)槭裁唇?jīng)常聽(tīng)說(shuō)說(shuō)類(lèi)別不能添加屬性呢朋腋?實(shí)際上,Category實(shí)際上允許添加屬性的膜楷,同樣可以使用@property旭咽,但是不會(huì)生成_變量(帶下劃線的成員變量),也不會(huì)生成添加屬性的getter和setter方法赌厅,所以穷绵,盡管添加了屬性,也無(wú)法使用點(diǎn)語(yǔ)法調(diào)用getter和setter方法特愿。那我們想要實(shí)現(xiàn)我們平時(shí)的屬性所具有的功能應(yīng)該怎么樣做呢仲墨?

其實(shí)我們可以使用runtime去做,使用runtime去實(shí)現(xiàn)Category為已有的類(lèi)添加新的屬性并生成getter和setter方法揍障。不要忘記了Objective-C是動(dòng)態(tài)語(yǔ)言目养。方法是通過(guò)runtime.h中objc_getAssociatedObject / objc_setAssociatedObject來(lái)訪問(wèn)和生成關(guān)聯(lián)對(duì)象。這兩個(gè)方法可以讓一個(gè)對(duì)象和另一個(gè)對(duì)象關(guān)聯(lián)毒嫡,就是說(shuō)一個(gè)對(duì)象可以保持對(duì)另一個(gè)對(duì)象的引用癌蚁,并獲取那個(gè)對(duì)象。

//NSObject+IndieBandName.h@interfaceNSObject(IndieBandName)@property(nonatomic,strong)NSString*indieBandName;@end

上面是頭文件聲明审胚,下面的實(shí)現(xiàn)的.m文件:

// NSObject+IndieBandName.m #import"NSObject+Extension.h"#importstaticconstvoid*IndieBandNameKey = &IndieBandNameKey;@implementationNSObject(IndieBandName)@dynamicindieBandName;- (NSString*)indieBandName {returnobjc_getAssociatedObject(self, IndieBandNameKey);}- (void)setIndieBandName:(NSString*)indieBandName { objc_setAssociatedObject(self, IndieBandNameKey, indieBandName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}@end

通過(guò)runtime的兩種方法就可以為類(lèi)別添加一個(gè)實(shí)例變量了匈勋。

形式的轉(zhuǎn)載都請(qǐng)聯(lián)系作者獲得授權(quán)并注明出處。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末膳叨,一起剝皮案震驚了整個(gè)濱河市洽洁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌菲嘴,老刑警劉巖饿自,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汰翠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡昭雌,警方通過(guò)查閱死者的電腦和手機(jī)复唤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)烛卧,“玉大人佛纫,你說(shuō)我怎么就攤上這事∽芊牛” “怎么了呈宇?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)局雄。 經(jīng)常有香客問(wèn)我甥啄,道長(zhǎng),這世上最難降的妖魔是什么炬搭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任蜈漓,我火速辦了婚禮,結(jié)果婚禮上宫盔,老公的妹妹穿的比我還像新娘融虽。我一直安慰自己,他們只是感情好飘言,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布衣形。 她就那樣靜靜地躺著驼侠,像睡著了一般姿鸿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上倒源,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天苛预,我揣著相機(jī)與錄音,去河邊找鬼笋熬。 笑死热某,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的胳螟。 我是一名探鬼主播昔馋,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼糖耸!你這毒婦竟也來(lái)了秘遏?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嘉竟,失蹤者是張志新(化名)和其女友劉穎邦危,沒(méi)想到半個(gè)月后洋侨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡倦蚪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年希坚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陵且。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡裁僧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出慕购,到底是詐尸還是另有隱情锅知,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布脓钾,位于F島的核電站售睹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏可训。R本人自食惡果不足惜昌妹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望握截。 院中可真熱鬧飞崖,春花似錦、人聲如沸谨胞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)胯努。三九已至牢裳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叶沛,已是汗流浹背蒲讯。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灰署,地道東北人判帮。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像溉箕,于是被迫代替她去往敵國(guó)和親晦墙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,089評(píng)論 1 32
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,321評(píng)論 8 265
  • 引導(dǎo) 對(duì)于從事 iOS 開(kāi)發(fā)人員來(lái)說(shuō)肴茄,所有的人都會(huì)答出「 Runtime 是運(yùn)行時(shí) 」晌畅,什么情況下用 Runtim...
    Winny_園球閱讀 4,188評(píng)論 3 75
  • 對(duì)于從事 iOS 開(kāi)發(fā)人員來(lái)說(shuō),所有的人都會(huì)答出【runtime 是運(yùn)行時(shí)】什么情況下用runtime?大部分人能...
    夢(mèng)夜繁星閱讀 3,697評(píng)論 7 64
  • 董Shen閱讀 602評(píng)論 0 0