OC語言特性

分類

用分類做了哪些事情

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

特點

  • 運行時決議:編好分類文件,并沒有分類中添加的內(nèi)容附加到相應(yīng)的宿主類批糟,而是在運行時通過RunTime真實的添加到相應(yīng)的宿主類
  • 可以為系統(tǒng)類添加分類

分類中都可以添加哪些內(nèi)容凶异?

  • 實例方法
  • 類方法
  • 協(xié)議
  • 屬性(分類中定義屬性蜀撑,實際上只是生成了對應(yīng)的getter、setter方法)
    Runtime的源碼分類的結(jié)構(gòu)體:struct _category_t

分類的調(diào)用棧(Category)

  • _objc_int -> map_2_images -> map_images_nolock -> _read_images -> remethodizeClass
    • images是鏡像
    • _read_images 加載一些可執(zhí)行文件到內(nèi)存當中進行處理
    • remethodizeClass
分類_objc_init調(diào)用棧.png

如果兩個分類添加同一個函數(shù)名稱的函數(shù)剩彬,哪一個函數(shù)最終生效酷麦?

取決于編譯順序,最后生成分類的函數(shù)會生效喉恋,前面的將被覆蓋掉沃饶。

總結(jié):

  • 分類添加的方法可以”覆蓋”原有方法
    ① 實際上是runtime在查找這個類的方法時,會查找分類一個宿主類的所有方法所在數(shù)組
    ② 而這個數(shù)組的分類方法是在宿主類前面的轻黑,所以說分類方法的調(diào)用有優(yōu)先宿主類
    ③ 而并不是覆蓋宿主類的方法糊肤。

  • 同名分類方法誰能生效取決于編譯順序
    最后被編譯的分類,會優(yōu)先生效

  • 名字相同的分類會引起編譯報錯
    生成具體分類苔悦,會把添加的分類名稱轩褐,以下劃線的形式拼接到宿主類中,這樣在添加過程中玖详,如果名稱一樣會報錯把介。

能否給分類添加”成員變量”勤讽?

不能在分類的聲明和定義實現(xiàn)的時候直接為分類添加成員變量,但是可以通過關(guān)聯(lián)對象的技術(shù)來為分類添加”成員變量”拗踢,來達到分類可以添加”成員變量的效果”脚牍。
關(guān)聯(lián)對象的3個API:

objc_setAssociatedObject(<#id  _Nonnull object#>, <#const void * _Nonnull key#>, <#id  _Nullable value#>, <#objc_AssociationPolicy policy#>)
objc_getAssociatedObject(<#id  _Nonnull object#>, <#const void * _Nonnull key#>)
objc_removeAssociatedObjects(<#id  _Nonnull object#>)

① 設(shè)定一個value值,通過key值建立一個映射關(guān)系巢墅,然后通過policy策略诸狭,關(guān)聯(lián)到object上
② 根據(jù)指定的key到object中獲取關(guān)聯(lián)的值
③ 根據(jù)對象,移除所有相關(guān)它的對象

我們用關(guān)聯(lián)對象技術(shù)來實現(xiàn)為分類添加”成員變量”君纫,這個成員變量會被添加到哪里驯遇?

① 我們?yōu)榉诸愃砑拥某蓡T變量肯定不是在宿主類中的。
② 關(guān)聯(lián)對象由AssociationsManager管理并在AssociationHashMap存儲蓄髓。
③ 我們創(chuàng)建的每一個對象的關(guān)聯(lián)對象實際上都存儲在了AssociationHashMap這樣的容器中叉庐。
④ 所有對象的關(guān)聯(lián)內(nèi)容都在同一個全局容器中
⑤ 不同對象的關(guān)聯(lián)對象的值都會放到全局容器中
⑥ 假如想消除一個關(guān)聯(lián)對象時,可以傳入value為nil操作來實現(xiàn)

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

關(guān)聯(lián)對象本質(zhì)

關(guān)聯(lián)對象由AssociationsManager管理并在AssociationHashMap存儲会喝。
我們創(chuàng)建的每一個對象的關(guān)聯(lián)對象實際上都存儲在了AssociationHashMap這樣的容器中陡叠。
所有對象的關(guān)聯(lián)內(nèi)容都在同一個全局容器中

利用關(guān)聯(lián)對象添加成員變量

1. - (void)setName:(NSString *)name { objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
2. - (NSString *)name
{
    // 隱式參數(shù)
    // _cmd == @selector(name)
    return objc_getAssociatedObject(self, _cmd);
}
(void)removeAssociatedObjects{
    // 移除所有關(guān)聯(lián)對象
    objc_removeAssociatedObjects(self);
}
關(guān)聯(lián)對象的本質(zhì).png
關(guān)聯(lián)對象的Json形式.png

擴展

類擴展一般都在宿主類的.m文件中。

一般用擴展做什么肢执?

  • 聲明私有屬性
  • 聲明私有方法(沒有多大作用枉阵,方便閱讀)
  • 聲明私有成員變量
    聲明私有屬性、聲明私有成員變量是有區(qū)別的

特點

  1. 分類是運行時決議预茄、擴展是編譯時決議
  2. 分類可以有聲明和實現(xiàn)兴溜,而擴展只有聲明的形式,實現(xiàn)是直接在宿主類的
  3. 可以為系統(tǒng)類添加分類反璃,但是不能為系統(tǒng)類添加擴展

代理

  • 準確的說是一種軟件設(shè)計模式
  • iOS 當中以@protocol形式體現(xiàn)
  • 傳遞方式一對一

代理的工作流程

三個角色:

  • 委托方
    ① 要求代理方需要實現(xiàn)的接口昵慌,也就是協(xié)議
    ② 調(diào)用代理方遵從協(xié)議的方法
    ③ 可能返回一個處理結(jié)果
  • 協(xié)議
    ① 可以定義方法(必須實現(xiàn)和可選類型)
    ② 可以定義屬性
  • 代理方
    按照協(xié)議實現(xiàn)方法


    代理的實現(xiàn)流程.png

代理方和委托方以什么關(guān)系存在?

一般聲明為weak來規(guī)避循環(huán)引用


代理循環(huán)引用.png

通知實現(xiàn)機制

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

如何實現(xiàn)通知的機制斋攀?假如說自己實現(xiàn)這種機制如何實現(xiàn)?

  • 實現(xiàn)一個實現(xiàn)一個全局Map
  • key為notificationName
  • value為一個Serrvers(因為一對多)梧田, servers中的每個元素應(yīng)該能明確哪一個對象淳蔼,哪一個方法

通知傳遞消息一對多的流程

通知一對多的流程.png

通知和代理的區(qū)別

  • 代理使用代理模式,而通知是由觀察者模式實現(xiàn)的
  • 代理是一對一裁眯,而通知是一對多

KVO

什么是KVO鹉梨?

  • KVO是key-value observing的縮寫
  • KVO是Objective-C對觀察者設(shè)計模式的又一實現(xiàn)
  • KVO是Objective-C對觀察者設(shè)計模式的又一實現(xiàn)

KVO的實現(xiàn)機制

KVOisa混寫.png
  • 系統(tǒng)調(diào)用addObserver添加KVO的時候
  • 會想被觀察者對象的isa指向其名為NSKVONotifying_<ObjectClass>子類
  • NSKVONotifying_<ObjectClass>中重寫了setter方法
  • 重寫的setter方法負責通知觀察者

重寫setter方法

  • -(void)willChangeValueForKey:(NSString *)key;
  • -(void)didChangeValueForKey:(NSString *)key;

通過KVC設(shè)置value能夠生效?

  • 通過KVC設(shè)置value穿稳,KVO的通知會生效
  • KVC設(shè)置value會調(diào)用setter方法

通過成員變量直接賦值value能否生效

  • 不會觸發(fā)系統(tǒng)的KVO的
  • 不會調(diào)用setter方法
  • 可以在變量賦值的代碼塊前后添加下面兩個API來觸發(fā)KVO
    ① -(void)willChangeValueForKey:(NSString *)key;
    ② -(void)didChangeValueForKey:(NSString *)key;

觀測方法的options

  • NSKeyValueObservingOptionOld 把更改之前的值提供給處理方法
  • NSKeyValueObservingOptionNew 把更改之后的值提供給處理方法
  • NSKeyValueObservingOptionInitial 把初始化的值提供給處理方法存皂,一旦注冊,立馬就會調(diào)用一次。通常它會帶有新值旦袋,而不會帶有舊值骤菠。
  • NSKeyValueObservingOptionPrior 分2次調(diào)用。在值改變之前和值改變之后疤孕。

總結(jié)

  • 使用setter方法改變值KVO才會生效
  • 使用setValue:forkey:改變KVO才會生效
  • 成員變量直接修改需手動添加KVO才會生效

KVC

什么是KVC商乎?

  • KVC是Key-value coding的縮寫
  • KVC的兩個API
    ① -(void)setValue:(nullable id)value forKey:(NSString *)key
    ② -(nullable id)valueForKey:(NSString *)key

使用KVC是否會違背于面向?qū)ο蟮木幊趟枷?/h2>

KVC的key是沒有限制的,如果我們知道這個對象內(nèi)部的私有變量名稱的話祭阀,我們可以在外界修改鹉戚、訪問它,從這個角度來考慮的話是會破壞面向?qū)ο蟮乃枷氲?/p>

valueForKey的實現(xiàn)流程

KVCGetter方法的流程.png

Accessor Method方法的定義

  • instance var
  • _key
  • _isKey
  • key
  • isKey

setValue:forKey的實現(xiàn)流程

KVCsetter方法的流程.png

Accessor Method方法的定義

  • set:
  • _set:
  • setIs:

instance var

  • _key
  • _isKey
  • key
  • isKey

屬性關(guān)鍵字

屬性關(guān)鍵字分為哪幾類

  • 讀寫權(quán)限
    ① readonly
    ② readwrite iOS默認
  • 原子性
    ① atomic iOS默認
    -修飾的是一個數(shù)組专控,賦值和獲取是線程安全的抹凳,
    -修改這個數(shù)組中的數(shù)據(jù)不是線程安全的 (例如在atomic修飾的NSMutableArray數(shù)組中,進行增刪元素操作)
    ② nonatomic
  • 引用技計數(shù)
    ① retain mrc
    ② strong arc
    ③ assign 既可以修飾對象伦腐,也可以修飾值類型數(shù)據(jù)
    ④ unsafe_unretained MRC使用的比較多却桶,ARC基本上不怎么用
    ⑤ weak
    ⑥ copy

assign的特點

  • 修飾基本數(shù)據(jù)類型,如果int蔗牡、bool等
  • 修飾對象類型時,不改變引用計數(shù)
  • 在對象釋放以后嗅剖,assign修飾的對象指針還是會指向這個對象地址辩越,當使用這個對象的時候,會出現(xiàn)野指針信粮。

weak 特點

  • 不改變對象引用計數(shù)
  • 所指對象在釋放之后會自動置為nil

assign和weak的區(qū)別有哪些黔攒?

1、weak只可以修飾對象强缘、而assign可以修飾基本數(shù)據(jù)類型和對象
2督惰、assign修飾的對象的時候,當對象被釋放掉以后旅掂,assign指針還是會指向?qū)ο蟮牡刂飞团撸鴚eak修飾的對象,在對象釋放后商虐,weak的指針會被置nil

copy

源對象類型 拷貝方式 目標對象類型 拷貝類型
mutable對象 copy 不可變 深拷貝
mutable對象 mutableCopy 可變 深拷貝
immutable對象 copy 不可變 淺拷貝
immutable對象 mutableCopy 可變 深拷貝

① 可變對象的copy和mutablecopy都是深拷貝
② 不可變對象的copy是淺拷貝觉阅,mutablecopy是深拷貝
③ copy方法返回的都是不可變對象

淺拷貝

  • 淺拷貝會增加被拷貝對象的引用計數(shù)
  • 并沒有發(fā)生新的內(nèi)存分配
    淺拷貝就是對內(nèi)存地址的復(fù)制,讓目標對象指針和源對象指向同一片內(nèi)存空間秘车。


    淺拷貝.png

深拷貝

  • 不會增加被拷貝對象的引用計數(shù)
  • 產(chǎn)生了內(nèi)存分配
    深拷貝讓目標對象指針和源對象指針指向兩片內(nèi)容相同的內(nèi)存空間


    深拷貝.png

深拷貝VS淺拷貝典勇?

  • 是否開辟新的內(nèi)存空間
  • 是否影響引用計數(shù)

@property(copy) NSMutableArray *array, 會產(chǎn)生什么樣的問題

最終結(jié)果是一個不可變的對象,那么你在修改這個數(shù)組的時候會崩潰

  • 如果賦值過來的是NSMutableArray叮趴,copy之后雖然是深拷貝割笙,但是返回的是NSArray
  • 如果賦值過來的是NSArray,copy之后是NSArray
  • 當修改array這個數(shù)組的時候就會出現(xiàn)崩潰問題

MST

1眯亦、MRC下如何重寫retain修飾變量的setter方法伤溉?

@property(nonatomic,retain)id obj;

- (void)setObj:(id)obj{
    //對象不等判斷
    //如果傳遞過來的obj對象是原來的obj對象
    //實際上也是在傳遞過來的obj對象release的操作般码,有可能會直接釋放掉了傳遞過來的對象,
    //這時候如果還去訪問被釋放的對象就會崩潰
    if(_obj != obj){
        [_obj release];
        _obj = [obj retain]
    }
}

2谈火、 分類的實現(xiàn)原理

  • 是由運行時來決議的
  • 不同分類侈询,同名函數(shù)名稱,誰最后生效糯耍,取決于扔字,誰最后參與編譯的同名分類方法會生效
  • 如果分類方法的名字和宿主的方法名稱一樣,那么分類的方法會覆蓋宿主類的方法温技,這里的覆蓋是runtime優(yōu)先處理數(shù)組靠前的方法革为,如果找到就調(diào)用。宿主類的同名方法還是存在的

3舵鳞、KVO實現(xiàn)原理是怎么樣的震檩?

  • KVO是系統(tǒng)基于觀察模式的一個實現(xiàn)
  • KVO通過isa的混寫技術(shù)來動態(tài)運行時去為某一個類添加子類,并重寫setter方法蜓堕,同時把原有類的isa指針指向這個子類

4抛虏、能否為分類添加實例變量?

  • 實例變量(成員變量)套才,即它只能添加屬性迂猴,setter/getter的聲明,但是沒有實現(xiàn)背伴,不能使用其父類的一些成員方法
  • 屬性是系統(tǒng)自動為我們生成的一個添加下劃線的實例變量沸毁,系統(tǒng)幫我們實現(xiàn)了setter/getter方法
  • 不使用屬性創(chuàng)建的實例變量,需要最后在@implementation中用synthesize生成set方法
    @synthesize name;(創(chuàng)建實例變量的setter傻寂、getter方法)息尺,@dynamic告訴編譯器,不自動生成getter/setter方法疾掰,
  • 為分類添加實例變量
    ① 使用關(guān)聯(lián)對象技術(shù)為分類添加“實例變量”(只是達到一個成員變量的效果搂誉,實際上并不是真正的添加了實例變量)
    ② 代碼實例
    .h文件
@interface CustomView (dd)

- (NSString *)name;
- (void)setName:(NSString *)name;

@end

.m

@implementation CustomView (dd)

/*
 * 使用關(guān)聯(lián)對象模擬實例變量
 * 使用objc_getAssociatedObject、objc_setAssociatedObject模擬『屬性』的存取方法
 */

- (NSString *)name{
    
    return objc_getAssociatedObject(self, _cmd);
    
}

- (void)setName:(NSString *)name{
    
    objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
}
@end
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末静檬,一起剝皮案震驚了整個濱河市勒葱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌巴柿,老刑警劉巖凛虽,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異广恢,居然都是意外死亡凯旋,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來至非,“玉大人钠署,你說我怎么就攤上這事』耐郑” “怎么了谐鼎?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長趣惠。 經(jīng)常有香客問我垒探,道長肝匆,這世上最難降的妖魔是什么垮斯? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任坪创,我火速辦了婚禮,結(jié)果婚禮上侍瑟,老公的妹妹穿的比我還像新娘唐片。我一直安慰自己,他們只是感情好涨颜,可當我...
    茶點故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布揽思。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上戳葵,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天,我揣著相機與錄音志衣,去河邊找鬼和二。 笑死废登,一個胖子當著我的面吹牛羽戒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播亡电,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拇勃,長吁一口氣:“原來是場噩夢啊……” “哼榆骚!你這毒婦竟也來了碉钠?” 一聲冷哼從身側(cè)響起栗弟,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤罗侯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體状飞,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡荐吉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年焙糟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片样屠。...
    茶點故事閱讀 39,754評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡穿撮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞧哟,到底是詐尸還是另有隱情混巧,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布勤揩,位于F島的核電站咧党,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏陨亡。R本人自食惡果不足惜傍衡,卻給世界環(huán)境...
    茶點故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望负蠕。 院中可真熱鬧蛙埂,春花似錦、人聲如沸遮糖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽欲账。三九已至屡江,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赛不,已是汗流浹背惩嘉。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留踢故,地道東北人文黎。 一個月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓惹苗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親耸峭。 傳聞我的和親對象是個殘疾皇子桩蓉,可洞房花燭夜當晚...
    茶點故事閱讀 44,654評論 2 354

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