OC基礎(chǔ)特性

基礎(chǔ)特性

一邑时、分類(Category)

問題1:你用分類都做了哪些事情?

  • 聲明私有方法
  • 分解體積龐大的類文件
  • 把Framework的私有方法公開

1.1、特點

  • 運行時決議
    編寫完成的分類文件坤学,并沒有把分類內(nèi)容添加到宿主類中。
    也就說宿主中還沒有分類中的方法报慕,而是在運行時深浮,通過runtime將分類的方法添加到宿主當中。
    這也是分類的最大特點眠冈,也是分類和擴展的最大區(qū)別飞苇。

  • 可以為系統(tǒng)類添加分類
    擴展不能為系統(tǒng)添加擴展

1.2:分類中都可以添加哪些內(nèi)容菌瘫?

  • 實例方法
  • 類方法
  • 協(xié)議
  • 屬性
    在分類中定義一個屬性,實際是只是生成了setter和getter方法布卡,并沒有在分類添加實例變量雨让。想要添加實例變量,可以通過關(guān)聯(lián)對象的方法忿等。

1.3栖忠、分類數(shù)據(jù)結(jié)構(gòu)

Category 是表示一個指向分類的結(jié)構(gòu)體的指針,其定義如下:
typedef struct objc_category *Category;
struct objc_category {
  //分類名
  char *category_name; 
  //分類所屬的類名
  char *class_name;
  //實例方法列表
  struct objc_method_list *instance_methods; 
  //類方法列表
  struct objc_method_list *class_methods; 
  //分類所實現(xiàn)的協(xié)議列表
  struct objc_protocol_list *protocols;
 //實例屬性列表
  struct property_list_t *instanceProperties;
}

1.4贸街、加載調(diào)用棧(了解)

加載調(diào)用棧

備注:

  • _objc_init:runtime初始化方法庵寞。
  • images:指的是鏡像

1.5薛匪、源碼分析

這里以添加實例方法舉例:
remethodizeClass開始入手分析(只列出主要代碼):

1.5.1

我們只分析分類當中實例方法添加的邏輯
因此在這里我們假設(shè) isMeta = NO

bool isMeta = cls->isMetaClass();
1.5.2

生成一個新的二維數(shù)組捐川,用來存放分類中的方法

method_list_t **mlists = (method_list_t **)
        malloc(cats->count * sizeof(*mlists));
1.5.3

遍歷分類數(shù)組,采用倒敘遍歷

//宿主分類的總數(shù)
int i = cats->count;
    while (i--) {
        //獲取一個分類
        auto& entry = cats->list[i];
        //獲取該分類的方法列表
        method_list_t *mlist = entry.cat->methodsForMeta(isMeta);
        if (mlist) {
            //最后編譯的分類逸尖,方法最先添加到分類數(shù)組中
            mlists[mcount++] = mlist;
            fromBundle |= entry.hi->isBundle();
        }
    }
1.5.4

獲取宿主類當中的rw數(shù)據(jù)古沥,其中包含宿主類的方法列表信息

auto rw = cls->data();
1.5.5

分類方法拼接到rw的methods上
參數(shù)/變量含義:
rw代表類。
methods代表類的方法列表娇跟。
attachLists方法:將含有mcount個元素的mlists拼接到rw的methods上岩齿。

rw->methods.attachLists(mlists, mcount);
1.5.6

attachLists方法解析
假設(shè)列表中原有元素總數(shù)為2(oldCount = 2)。
假設(shè)將要添加的分類元素總數(shù)為3(addedCount = 3)逞频。
[ [method_t , method_t], [method_t],
[method_t , method_t , method_t] ]

這里只分析有數(shù)組的情況

//列表中原有元素總數(shù)。假設(shè)oldCount = 2
uint32_t oldCount = array()->count;
//拼接之后的元素總數(shù)
uint32_t newCount = oldCount + addedCount;
//根據(jù)新總數(shù)重新分配內(nèi)存
setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
//重新設(shè)置元素總數(shù)
array()->count = newCount;
/*
內(nèi)存移動
[ [ ], [ ], [ ], [原有的第一個元素], [原有的第二個元素]]
*/
memmove(array()->lists + addedCount, array()->lists, 
                    oldCount * sizeof(array()->lists[0]));
/*
內(nèi)存拷貝
[
    A ---> [addedLists中的第一個元素],
    B ---> [addedLists中的第二個元素],
    C ---> [addedLists中的第三個元素],
    [原有的第一個元素],
    [原有的第二個元素]
]
這也是分類方法會"覆蓋"宿主類的方法的原因
*/
memcpy(array()->lists, addedLists, 
                   addedCount * sizeof(array()->lists[0]));

問題2:一個類的多個分類包含同名方法栋齿,最后哪個會生效苗胀?

解釋:
誰最后編譯,誰就生效瓦堵。

1.6基协、分類總結(jié)

  • 分類添加的方法可以"覆蓋"原類方法
    效果上是"覆蓋",實際上原類方法還是存在的菇用。
  • 同名分類方法誰能生效取決于編譯順序
  • 名字相同的分類會引起編譯報錯

二澜驮、關(guān)聯(lián)對象

問題3:能否給分類添加成員變量?

解釋:
可以添加惋鸥。
在分類的聲明時杂穷,不能添加成員變量;但是可以通過關(guān)聯(lián)對象的方法添加卦绣。

問題4:給分類添加的成員變量是否添加到宿主中耐量?

解釋:
沒有添加到宿主中。被存放在一個全局容器中滤港,并且為不同類添加的關(guān)聯(lián)對象都放在同一個全局容器中廊蜒。

2.1、獲取屬性值

objc_getAssociatedObject(id object, const void *key);
  • object
    目標對象。即獲取哪個對象的關(guān)聯(lián)屬性
  • key
    根據(jù)對應(yīng)的key查找對象的屬性

2.2山叮、添加并設(shè)置屬性值

objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
  • object
    目標對象著榴。給自己添加屬性,就用self屁倔。
  • key
    屬性名脑又。
  • value
    關(guān)聯(lián)值。
  • policy
    策略汰现。屬性以什么形式保存挂谍。
    主要形式有以下幾種:
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,  // 指定一個弱引用相關(guān)聯(lián)的對象
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, // 指定相關(guān)對象的強引用,非原子性
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,  // 指定相關(guān)的對象被復(fù)制瞎饲,非原子性
    OBJC_ASSOCIATION_RETAIN = 01401,  // 指定相關(guān)對象的強引用口叙,原子性
    OBJC_ASSOCIATION_COPY = 01403     // 指定相關(guān)的對象被復(fù)制,原子性   
};

2.3嗅战、移除所有的關(guān)聯(lián)對象

objc_removeAssociatedObjects(id object);

2.4妄田、關(guān)聯(lián)對象的本質(zhì)

  • 關(guān)聯(lián)對象由AssociationsManager管理;并在AssociationsHashMap存儲驮捍。
  • 所有對象的關(guān)聯(lián)內(nèi)容都在同一個全局容器中疟呐。
關(guān)聯(lián)對象本質(zhì)
json對比

這里包含三部分數(shù)據(jù)結(jié)構(gòu):

  • AssociationsManager
    管理對象,里面有一個AssociationsHashMap對象东且。
  • AssociationsHashMap
    可以理解為全局容器启具。
    由多個obj:ObjectAssociationMap組成。
    一個實例對象就對應(yīng)一個ObjectAssociationMap珊泳。
  • ObjectAssociationMap
    由多個屬性名key:ObjcAssociation組成鲁冯。
  • ObjcAssociation
    由value和policy組成。

由上面可以知道色查,關(guān)聯(lián)對象沒有存放到原來的對象里面薯演,而是自己維護了一個全局map來存放的

問題5:怎樣清除一個關(guān)聯(lián)對象秧了?

解釋:
通過objc_setAssociatedObject跨扮,將其中value傳值為nil,就可以了验毡。

三衡创、擴展(Extension)

  • 聲明私有屬性
  • 聲明私有方法(只是為了方便閱讀,無太大作用)
  • 聲明私有變量

問題6:屬性和變量的區(qū)別晶通?

屬性 = 變量 + set方法 + get方法

問題7:分類和擴展的區(qū)別钧汹?

  • 擴展是編譯時決議,分類是運行時決議
  • 擴展是以聲明的形式存在录择,不是獨立的存在碗降,多數(shù)寄存于宿主類.m文件中;而分類是單獨存在的塘秦。
  • 不能為系統(tǒng)類添加擴展讼渊;但是可以為系統(tǒng)的類添加分類。

四尊剔、代理

  • 是一種軟件設(shè)計模式爪幻。
  • iOS中以@protocal形式體現(xiàn)。
  • 傳遞方式是一對一须误。

問題8:代理的工作流程是什么挨稿?

代理工作流程

問題9:為什么代理聲明的時候,要使用weak?

因為代理方一般強引用委托方京痢,為了防止循環(huán)引用奶甘,委托方必須對代理方進行弱引用。


代理

五祭椰、通知

  • 使用觀察者模式來實現(xiàn)的臭家,用于跨層傳遞消息的機制。
  • 傳遞方式為一對多方淤。

問題10:通知和代理的區(qū)別钉赁?

  • 代理是由代理模式實現(xiàn)的;通知是由觀察者模式實現(xiàn)的携茂。
  • 代理傳遞是一對一你踩,通知是一對多

問題11:如何實現(xiàn)通知機制讳苦?

通知原理

在通知中心带膜,內(nèi)部維護一個Map表,它的key是通知名稱医吊,value是觀察者表List钱慢。觀察者表List內(nèi)部包含多個observer對象逮京;observer對象包含通知接收的觀察者卿堂,觀察者調(diào)用的方法等等。

六懒棉、KVO

6.1草描、概念

  • KVO是Key-value observing的縮寫。
  • KVO是OC對觀察者設(shè)計模式的又一實現(xiàn)策严。
  • Apple使用了isa混寫(isa-swizzling)來實現(xiàn)KVO穗慕。

6.2、KVO調(diào)用發(fā)生過程圖

過程圖
  • A類對象調(diào)用系統(tǒng)方法addObserver:forKeyPath:options:context:
  • 在運行時會創(chuàng)建一個NSKVONotifying_A類妻导,這個NSKVONotifying_A類A類的子類
  • 此時逛绵,A類的isa指針會指向NSKVONotifying_A
  • 然后在NSKVONotifying_A中會重寫setter方法
  • 在重寫的setter方法中怀各,先調(diào)用willChangeValueForKey: ??調(diào)用父類方法,給父類賦值??給子類屬性賦值??調(diào)用didChangeValueForKey:??最終會調(diào)用observeValueForKeyPath通知了所有的觀察者术浪。

問題12:isa混寫技術(shù)在KVO中是怎么體現(xiàn)的瓢对?

見6.2.KVO調(diào)用發(fā)生過程圖

6.3、重寫setter方法的具體實現(xiàn)

6.3.1胰苏、兩個重要方法
重寫方法
6.3.2硕蛹、具體實現(xiàn)
具體實現(xiàn)

備注:

  • 一定會調(diào)用父類方法實現(xiàn),否則數(shù)值不統(tǒng)一硕并。
  • didChangeValueForKey調(diào)用后會觸發(fā)observeValueForKeyPath方法法焰。

問題13:通過KVC設(shè)置value能否生效?

可以生效

問題14:為什么通過KVC設(shè)置value能生效倔毙?

因為KVC內(nèi)部原理表明埃仪,這樣設(shè)置value會調(diào)用obj對象的setter方法

問題15:通過成員變量直接賦值value能夠生效普监?

  • 不能贵试。
  • 可以手動觸發(fā)KVO,在給變量賦值的代碼前后加入willChangeValueForKey:didChangeValueForKey:
  • 代碼如下:


    手動KVO

6.4凯正、KVO總結(jié)

  • 使用setter方法改變值KVO才生效毙玻。
  • 使用setValue:forKey:改變值KVO才會生效。
  • 成員變量直接修改需手動添加KVO才會生效廊散。

七桑滩、KVC

問題16:什么是KVC

  • 鍵值編碼技術(shù)、Key-value coding縮寫
  • (id)valueForKey: (NSString *)key
  • (void)setValue:(id)value forKey:(NSString *)key

問題17:KVC會不會破壞面向?qū)ο蟮木幊趟枷耄?/h3>

會破壞允睹。
因為上面的key是沒有限制的运准,即使是私有變量,也可以通過KVC設(shè)置私有變量的value缭受。

7.1胁澳、valueForKey系統(tǒng)實現(xiàn)流程

7.1.1、流程圖
valueForKey
  • 先查找對應(yīng)的get方法是否存在米者。
    如果存在韭畸,則調(diào)用對應(yīng)方法,結(jié)束流程蔓搞。
    如果不存在胰丁,則查找對應(yīng)的實例變量是否存在。
  • 查找實例變量是否存在喂分。
    系統(tǒng)提供了一個開關(guān)函數(shù)accessInstanceVariablesDirectly锦庸,默認是YES,允許查詢相同相似實例變量蒲祈。
    如果實例變量存在甘萧,則獲取當前值返回萝嘁。
  • 如果實例變量不存在,則會調(diào)用valueForUndefinedKey方法扬卷,拋出一個NSUndefinedKeyException異常酿愧。
7.1.2、流程圖 get方法是否存在的判斷規(guī)則
  • <getKey>
  • <key>
  • <isKey>
    如果有以上命名的訪問器方法邀泉,則默認當前get方法是存在的嬉挡。
7.1.3、流程圖 實例方法是否存在的判斷規(guī)則
  • _key
  • _isKey
  • key
  • isKey
    如果找到上述同名或者類似的變量汇恤,則默認當前的成員變量是存在的庞钢。

7.2、setValue:forKey:系統(tǒng)實現(xiàn)流程

7.2.1因谎、流程圖

setValue:forKey:
  • 先查找對應(yīng)的set方法是否存在基括。
    如果存在,則調(diào)用對應(yīng)方法财岔,結(jié)束流程风皿。
    如果不存在,則查找對應(yīng)的實例變量是否存在匠璧。
  • 其余步驟同valueForKey相同桐款。

八、屬性關(guān)鍵字

8.1夷恍、屬性關(guān)鍵字分類:

1魔眨、讀寫權(quán)限

  • readonly
  • readwrite(默認關(guān)鍵字)

2、 原子性

  • atomic(系統(tǒng)默認)
    可以賦值和獲取是線程安全的酿雪。但是操作對象是無法保證線程安全的遏暴。
    比如:一個數(shù)組Array。如果對Array進行賦值或獲取是線程安全的指黎,如果對Array進行操作(添加/移除對象)朋凉,則無法保證線程安全
  • nonatomic

3、 引用計數(shù)

  • retain/strong
    retain:MRC
    strong:ARC
  • assign/unsafe_unretained
    unsafe_unretained:ARC基本不使用
  • weak

8.2醋安、assign特點

  • 修飾基本數(shù)據(jù)類型杂彭,如int、Bool等茬故。
  • 修飾對象類型時盖灸,不改變其引用計數(shù)蚁鳖。
  • 會產(chǎn)生懸垂指針磺芭。
    assign指針指向的對象被釋放后,assgin指針仍然指向原對象內(nèi)存地址醉箕。

8.2钾腺、weak特點

  • 不改變被修飾對象的引用計數(shù)徙垫。
  • 所指對象在被釋放后會自動置為nil。

問題18:assgin與weak區(qū)別

  • 修飾數(shù)據(jù)類型方面
    assign既可以修飾基本數(shù)據(jù)類型放棒,也可以修飾對象姻报。
    weak只可以修飾對象。
  • 指針
    assgin可以產(chǎn)生懸垂指針间螟。
    weak指針自動指向nil吴旋。
    二者的共同點:都不影響引用計數(shù)。

8.3厢破、copy

問題19:見下圖

copy面試題
  • 如果賦值過來的是NSMutableArray荣瑟,copy之后是NSArray。
  • 如果賦值過來的是NSArray摩泪,copy之后是NSArray笆焰。
    因為最終array是NSArray,不可變對象见坑。
8.3.1嚷掠、深拷貝和淺拷貝
  • 是否開辟新的內(nèi)存空間
    深拷貝會,淺拷貝不會

  • 是否影響引用計數(shù)
    深拷貝不會荞驴,淺拷貝會


    總結(jié)
  • 可變對象的copy和mutableCopy都是深拷貝不皆。

  • 不可變對象的copy是淺拷貝,mutableCopy都是深拷貝熊楼。

  • copy方法返回的都是不可變對象粟焊。

九、筆試題總結(jié)

9.1孙蒙、MRC下如何重寫retain修飾變量的setter方法项棠?

MRC

9.2、請簡述分類的實現(xiàn)原理

1挎峦、分類的實現(xiàn)原理是由運行時決議的香追。
2、不同分類的含有同名分類方法坦胶,誰最后編譯透典,誰就生效。
3顿苇、如果分類中的方法恰好與目標類中的方法同名峭咒,分類會覆蓋同名的目標類方法。

9.3纪岁、KVO的實現(xiàn)原理是怎樣的凑队?

1、KVO是系統(tǒng)關(guān)于觀察者模式的一種體現(xiàn)幔翰。
2漩氨、KVO運用了isa混寫技術(shù)西壮;在動態(tài)運行時,為某一個類動態(tài)添加一個子類叫惊,重寫了它的setter方法款青;將原有類的isa指針指向新創(chuàng)建的子類。

9.4霍狰、能否為分類添加成員變量抡草?

不能。因為它的數(shù)據(jù)結(jié)構(gòu)中蔗坯,沒有成員變量渠牲。
可以通過關(guān)聯(lián)對象


問題1:什么是分類步悠?分類的原理和實現(xiàn)機制是什么签杈?

問題5:KVO實現(xiàn)機制?

問題6:KVC實現(xiàn)機制鼎兽?

問題7:屬性關(guān)鍵字答姥?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谚咬,隨后出現(xiàn)的幾起案子鹦付,更是在濱河造成了極大的恐慌,老刑警劉巖择卦,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敲长,死亡現(xiàn)場離奇詭異,居然都是意外死亡秉继,警方通過查閱死者的電腦和手機祈噪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尚辑,“玉大人辑鲤,你說我怎么就攤上這事「懿纾” “怎么了月褥?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瓢喉。 經(jīng)常有香客問我宁赤,道長,這世上最難降的妖魔是什么栓票? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任决左,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哆窿。我一直安慰自己,他們只是感情好厉斟,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布挚躯。 她就那樣靜靜地躺著,像睡著了一般擦秽。 火紅的嫁衣襯著肌膚如雪码荔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天感挥,我揣著相機與錄音缩搅,去河邊找鬼。 笑死触幼,一個胖子當著我的面吹牛硼瓣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播置谦,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼堂鲤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了媒峡?” 一聲冷哼從身側(cè)響起瘟栖,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谅阿,沒想到半個月后半哟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡签餐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年寓涨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氯檐。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡缅茉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出男摧,到底是詐尸還是另有隱情蔬墩,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布耗拓,位于F島的核電站拇颅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏乔询。R本人自食惡果不足惜樟插,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧黄锤,春花似錦搪缨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至流强,卻和暖如春痹届,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背打月。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工队腐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奏篙。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓柴淘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親秘通。 傳聞我的和親對象是個殘疾皇子悠就,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,101評論 1 32
  • 1.設(shè)計模式是什么梗脾? 你知道哪些設(shè)計模式,并簡要敘述盹靴?設(shè)計模式是一種編碼經(jīng)驗炸茧,就是用比較成熟的邏輯去處理某一種類型...
    龍飝閱讀 2,151評論 0 12
  • 前言:面試筆試都是必考語法知識點。請認真復(fù)習(xí)和深入研究OC稿静。 目錄:iOS-面試題-OC基礎(chǔ)篇 (1) - (84...
    麥穗0615閱讀 4,260評論 0 33
  • KVC(Key-value coding)鍵值編碼梭冠,單看這個名字可能不太好理解。其實翻譯一下就很簡單了改备,就是指iO...
    我的夢工廠閱讀 891評論 1 8
  • 2018年8月18日 星期六 晴 昨夜的夢很清晰控漠,很早就醒了。 夢中都是熟悉的人悬钳,仿佛是在一間大教室里盐捷,有教會的...
    紅主兒閱讀 918評論 3 5