iOS面試題:@protocol 和 category 中如何使用 @property

  1. 在 protocol 中使用 property 只會生成 setter 和 getter 方法聲明琼讽,我們使用屬性的目的痢站,是希望遵守我協(xié)議的對象能實(shí)現(xiàn)該屬性。在實(shí)現(xiàn) protocol 的類中如果要使用 property 對應(yīng)的實(shí)例變量,則需要做一下 @synthesize var = _var;齿穗。

  2. 在 category 中增加屬性的目的主要為了解耦,在很多第三方框架中會使用饺律。在 category 中使用 @property 只會生成 setter 和 getter 方法的聲明窃页,并不會自動生成實(shí)例變量以及存取方法,Xcode 會警告需要手動實(shí)現(xiàn) setter 和 getter 方法。這是因?yàn)?category 它是在運(yùn)行時決定的脖卖。在編譯時乒省,對象的內(nèi)存布局已經(jīng)確定,如果添加實(shí)例變量就會破壞類的內(nèi)部布局畦木,這對編譯型語言來說是災(zāi)難性的袖扛。所以一般使用 runtime 中的關(guān)聯(lián)對象為已經(jīng)存在的類添加屬性。關(guān)聯(lián)對象類似于成員變量十籍,不過是在運(yùn)行時添加的蛆封。在 runtime 中所有的關(guān)聯(lián)對象都由 AssociationsManager 管理。AssociationsManager 里面是由一個靜態(tài) AssociationsHashMap 來存儲所有的關(guān)聯(lián)對象的勾栗。這相當(dāng)于把所有對象的關(guān)聯(lián)對象都存在一個全局 map 里面惨篱。而 map 的 key 是這個對象的指針地址(任意兩個不同對象的指針地址一定是不同的),而這個 map 的 value 又是另外一個 AssociationsHashMap围俘,里面保存了關(guān)聯(lián)對象的 KV 對砸讳。runtime 的銷毀對象函數(shù) objc_destructInstance里面會判斷這個對象有沒有關(guān)聯(lián)對象,如果有楷拳,會調(diào)用 _object_remove_assocations 做關(guān)聯(lián)對象的清理工作绣夺。

如果我們真的需要給 category 增加屬性的實(shí)現(xiàn),需要借助于運(yùn)行時的兩個函數(shù):

設(shè)置關(guān)聯(lián)對象

objc_setAssociatedObject(<#id object#>, <#const void *key#>, <#id value#>, <#objc_AssociationPolicy policy#>)
1.第一個參數(shù):  id object : 需要傳入的是 : 對象的主分支
2.第二個參數(shù):  const void *key : 是一個 static 類型的 關(guān)鍵字,這里根據(jù)開發(fā)者自身來定義就行(盡量寫的有根據(jù)一點(diǎn),避免以后忘記是干啥用的)
3.第三個參數(shù):  id value : 傳入的是: 對象的子分支
4.第四個參數(shù): objc_AssociationPolicy policy :是當(dāng)前關(guān)聯(lián)對象的類型 strong,weak,copy (枚舉類型:開發(fā)者可以點(diǎn)進(jìn)去看)

①主分支:如果將一個label控件和控制器關(guān)聯(lián)上,而且放在控制器上面,那么這個控制器對象 self 或者 self.view 就充當(dāng)主分支
②子分支 : 那么這個label 就充當(dāng) 子分支
③如果 控制器上有兩個控件, 一個Label, 一個 View, 那么想這兩個控件 弄上關(guān)聯(lián)關(guān)系, 這兩個控件隨意一個做主分支,一個做子分支(這個根據(jù)開發(fā)場景而定)

獲取關(guān)聯(lián)對象

objc_getAssociatedObject(<#id object#>, <#const void *key#>)就相對來說容易理解一點(diǎn)了
1.第一個參數(shù) : 主分支
2.第二個參數(shù) : 關(guān)鍵字

示例:

// MyView+MyCategory.h
#import "MyView.h"

@interface MyView (MyCategory)

// 在 Category 中定義屬性:
@property (assign, nonatomic) int32_t viewIndex;

@end

// MyView+MyCategory.m
#import "MyView+MyCategory.h"
#import <objc/runtime.h>

// 標(biāo)記屬性的 Key:
static const void *ViewIndexKey = &ViewIndexKey;

@implementation MyView (MyCategory)

@dynamic viewIndex;

- (void)setViewIndex:(int32_t)viewIndex {
    objc_setAssociatedObject(self, ViewIndexKey, @(viewIndex), OBJC_ASSOCIATION_ASSIGN);
}

- (int32_t)viewIndex {
    return [objc_getAssociatedObject(self, ViewIndexKey) intValue];
}

@end

另外

    // 釋放關(guān)聯(lián)對象
    // 第三個參數(shù), 設(shè)為 nil, 則將 self 與 nil 關(guān)聯(lián)... 也等同于 : 沒關(guān)聯(lián)任何對象
    objc_setAssociatedObject(self, &overView, nil, OBJC_ASSOCIATION_ASSIGN);
    
    // 移除 所有關(guān)聯(lián)對象 : 這個方法 相當(dāng)于 初始化 arr 對象一樣(并不是初始化arr這個指針?biāo)赶虻膬?nèi)存地址)
    objc_removeAssociatedObjects(self);

擴(kuò)展一下:到別人代碼塊里頭會用到 _cmd 這個關(guān)鍵字

此關(guān)鍵字代表的是什么?

- (UILabel *)textLabel{
    return objc_getAssociatedObject(self, _cmd);
}

上面代碼 直接通過 objc_getAssociatedObject方法獲取到 textLabel 關(guān)聯(lián)的關(guān)鍵字, 或者 對象本身 或者 Bool 等等
而關(guān)鍵在于下面一個句代碼:

- (void)setTextLabel:(UILabel *)textLabel{
    objc_setAssociatedObject(self, @selector(textLabel), textLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

_cmd :第一句返回的時候,相當(dāng)于返回一個 id對象 ,而關(guān)鍵字則是 : textLabel ,它是根據(jù)當(dāng)前方法,直接使用方法的名稱欢揖,即 - (***)textLabel 方法陶耍,并且能保證改名稱不重復(fù).(第一句代碼方法名 : textLabel ,因?yàn)橐粋€類中不可能用相同的方法名)

第二句代碼中出現(xiàn) @selector(textLabel),這里它就調(diào)用第一句代碼了, @selector直接返回SEL,則獲取到textLabel的方法名,則為第一句代碼返回的值.

1:上面兩個方法 寫在一個 單獨(dú)的View中,在這個類的 .h中,創(chuàng)建一個 weak(若引用)的textLabel,而在.m文件中 initWithFrame中直接創(chuàng)建self.textLabel = [[UILabel alloc] initWithFrame:self.bounds];并添加到這個view上
2:那么按照常理來說, 這里應(yīng)該報(bào)警告, 但是 在控制器中打印 這個類的 textLabel , 你會發(fā)現(xiàn)是有內(nèi)存的, 如果把第一句和第二句代碼注釋掉, 打印則沒有內(nèi)存.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市她混,隨后出現(xiàn)的幾起案子烈钞,更是在濱河造成了極大的恐慌,老刑警劉巖坤按,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毯欣,死亡現(xiàn)場離奇詭異,居然都是意外死亡臭脓,警方通過查閱死者的電腦和手機(jī)酗钞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來来累,“玉大人砚作,你說我怎么就攤上這事∴谒” “怎么了葫录?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長领猾。 經(jīng)常有香客問我米同,道長骇扇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任面粮,我火速辦了婚禮少孝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘但金。我一直安慰自己韭山,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布冷溃。 她就那樣靜靜地躺著,像睡著了一般梦裂。 火紅的嫁衣襯著肌膚如雪似枕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天年柠,我揣著相機(jī)與錄音凿歼,去河邊找鬼。 笑死冗恨,一個胖子當(dāng)著我的面吹牛答憔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播掀抹,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼虐拓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了傲武?” 一聲冷哼從身側(cè)響起蓉驹,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎揪利,沒想到半個月后态兴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疟位,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年瞻润,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甜刻。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡绍撞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出罢吃,到底是詐尸還是另有隱情楚午,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布尿招,位于F島的核電站矾柜,受9級特大地震影響阱驾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜怪蔑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一里覆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缆瓣,春花似錦喧枷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至渡冻,卻和暖如春戚扳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背族吻。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工帽借, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人超歌。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓砍艾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親巍举。 傳聞我的和親對象是個殘疾皇子脆荷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

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