Objective-C語言特性相關(guān)

1.分類相關(guān)

(1)特點:
  • 運(yùn)行時決議
    在編好分類文件之后莱睁,它并沒有將分類當(dāng)中對應(yīng)添加的內(nèi)容附加到相應(yīng)的宿主類中是己,實際上宿主類中還沒有分類中方法婿斥,而是在運(yùn)行時竖配,通runtime將分類中添加的內(nèi)容添加到宿主類中。
  • 可以為系統(tǒng)類添加分類
(2)實戰(zhàn)

分類中可以添加哪些內(nèi)容斩熊?

  • 實例方法
  • 類方法
  • 協(xié)議
  • 屬性(我們在分類中定義一個屬性往枣,實際上只是生成了對應(yīng)的get方法和set方法,并沒有為我們在分類中添加實例變量)

你用分類都做了哪些事情粉渠?

  • 聲明私有方法
  • 分解體積龐大的類文件
  • 把Framework的私有方法公開
(3)分類的結(jié)構(gòu)體
截圖.png
(4)分類加載調(diào)用棧
截圖1.png
static void remethodizeClass(Class cls){
category_list *cats;
bool isMeta;
runtimeLock.assertWriting();
/*
 我們只分析分類當(dāng)中實例方法添加的邏輯
 因此在這里我們假設(shè) isMeta = NO
*/
isMeta = cls->isMetaClass();
// Re-methodizing: check for more categories
// 獲取cls中未完成整合的所有分類
if ((cats = unattachedCategoriesForClass(cls, false/*not realizing*/))) {
    if (PrintConnecting) {
        _objc_inform("CLASS: attaching categories to class '%s' %s", 
                     cls->nameForLogging(), isMeta ? "(meta)" : "");
    }
    attachCategories(cls, cats, true /*flush caches*/);        
    free(cats);
}}      
 static void attachCategories(Class cls, category_list *cats, bool flush_caches){
     if (!cats) return;
     if (PrintReplacedMethods) printReplacements(cls, cats);
     /*
       我們只分析分類當(dāng)中實例方法添加的邏輯分冈,
      因此在這里我們假設(shè)isMeta = NO
    */
    bool isMeta = cls->isMetaClass();
   /*
  二維數(shù)組 [[method_t, method_t,...],[method_t, method_t,...],                               [method_t, method_t,...],...]
  */
   method_list_t **mlists = (method_list_t **)
    malloc(cats->count * sizeof(*mlists));
   property_list_t **proplists = (property_list_t **)
    malloc(cats->count * sizeof(*proplists));
   protocol_list_t **protolists = (protocol_list_t **)
    malloc(cats->count * sizeof(*protolists));
   // Count backwards through cats to get newest categories first
   int mcount = 0;
   int propcount = 0;
   int protocount = 0;
   int i = cats->count;
   bool fromBundle = NO;
   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();
     }
     //屬性列表添加規(guī)則 同方法列表添加規(guī)則
      property_list_t *proplist = 
      entry.cat->propertiesForMeta(isMeta, entry.hi);
      if (proplist) {
        proplists[propcount++] = proplist;
      }
      protocol_list_t *protolist = entry.cat->protocols;
      if (protolist) {
         protolists[protocount++] = protolist;
     }
  }
  auto rw = cls->data();
  prepareMethodLists(cls, mlists, mcount, NO, fromBundle);
// 添加方法
  rw->methods.attachLists(mlists, mcount);
 free(mlists);
  if (flush_caches  &&  mcount > 0) flushCaches(cls);
// 添加屬性
  rw->properties.attachLists(proplists, propcount);
  free(proplists);
// 添加協(xié)議
  rw->protocols.attachLists(protolists, protocount);
  free(protolists);
 }

如果兩個分類中都有一個同名的方法霸株,最后編譯的分類當(dāng)中的同名方法才會最終生效雕沉。

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

能否給分類添加"成員變量" ?

  id objc_getAssociatedObject(id object,const void * key)
  void objc_setAssociatedObject(id object,const void *key,id value,objc_AssociationPolicy policy)
  void objc_removeAssociatedObjects(id object)

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

截圖2.png

截圖3.png

3.擴(kuò)展屬性

(1) 特點
  • 編譯時決議
  • 只以聲明的形式存在去件,多數(shù)情況下寄生于宿主類.m中坡椒。
  • 不能為系統(tǒng)類添加擴(kuò)展。
(2) 一般用擴(kuò)展做什么尤溜?
  • 聲明私有屬性
  • 聲明私有方法
  • 聲明私有成員變量

4.代理

準(zhǔn)確的說是一種軟件設(shè)計模式倔叼,iOS當(dāng)中以@protocol形式體現(xiàn),傳遞方式一對一靴跛。

工作流程

截圖1.png

注意點
一般聲明為weak以規(guī)避循環(huán)引用缀雳。

截圖2.png

5.通知

概念:通知是使用觀察者模式來實現(xiàn)的用于跨層傳遞消息的機(jī)制,傳遞方式為一對多梢睛。

截圖3.png

如何實現(xiàn)通知機(jī)制肥印?
截圖4.png

6.KVO

  • KVO是Objective-C對觀察者設(shè)計模式的一種實現(xiàn)
  • apple使用了isa混寫(isa-swizzling)來實現(xiàn)KVO


    截圖5.png
  • 使用setter方法改變值kvo才會生效。
  • 使用setValue:forkey:改變KVO才會生效
  • 成員變量直接修改需求手動添加KVO才會生效绝葡。
#import <Foundation/Foundation.h>
@interface MObject : NSObject
@property (nonatomic,assign)int value;
- (void)increase;
@end

#import "MObject.h"
@implementation MObject
- (instancetype)init{
    self = [super init];
    if(self){
        _value = 0;
    }
    return self;
}
- (void)increase{
    _value = _value + 1;
}
@end

#import <Foundation/Foundation.h>
@interface MObserver : NSObject
@end

#import "MObserver.h"
#import "MObject.h"
@implementation MObserver
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if([object isKindOfClass:[MObject class]] && [keyPath isEqualToString:@"value"]){
        NSNumber *valueNum = [change valueForKey:NSKeyValueChangeNewKey];
        NSLog(@"value is %@",valueNum);
    }
}
@end

截圖6.png

打印結(jié)果
截圖7.png

NSKVONotifying_A的setter實現(xiàn)

- (void)setValue:(id)value forKey:(NSString *)key{
    [self willChangeValueForKey:@"keyPath"];
    //調(diào)用父類實現(xiàn)深碱,也即原類的實現(xiàn)
    [super setValue:value forKey:key];
    [self didChangeValueForKey:@"keyPath"];
}

問題

  1. 通過kvc設(shè)置value能否生效?
    2.通過成員變量直接賦值value能否生效藏畅?

7.KVC

蘋果系統(tǒng)為我們提供的一種鍵值編碼技術(shù)敷硅。

(1) -(id)valueForKey:(NSString *)key
截圖8.png
a.Accessor Method
  • <getKey>
  • <key>
  • <isKey>
b.Instance var
  • _key
  • _isKey
  • key
  • isKey
(2)-(void)setValue:(id)value forKey:(NSString *)key
截圖9.png

8.屬性關(guān)鍵字

  • 讀寫權(quán)限
  • 原子性
  • 引用技術(shù)
(1)讀寫權(quán)限
  • readonly
  • readwrite
(2)原子性
  • atomic (賦值和獲取是線程安全的)
    例如一個數(shù)組使用atomic關(guān)鍵字功咒,對數(shù)組進(jìn)行賦值和獲取是線程安全的,但是對數(shù)組進(jìn)行添加數(shù)據(jù)绞蹦,刪除數(shù)據(jù)力奋,不是線程安全的
  • nonatomic
(3)引用計數(shù)
  • retain/strong

  • assign/unsafe_unretained

  • weak

  • copy
    assign

    • 修飾基本數(shù)據(jù)類型,如int , BOOL等
    • 修飾對象類型時幽七,不改變其引用計數(shù)
    • 會產(chǎn)生懸垂指針(assign所修飾的對象被釋放后景殷,assign指針仍然指向原對象內(nèi)存地址,這時通過assign繼續(xù)訪問對象澡屡,由于懸垂指針的存在猿挚,會導(dǎo)致程序內(nèi)存泄漏或者程序異常)

    weak
    - 不改變修飾對象的引用計數(shù)。
    - 所指對象在被釋放之后驶鹉,weak指針會自動置為nil

    copy
    (a) 淺拷貝
    特點:1.增加被拷貝對象的引用計數(shù) 2.并沒有發(fā)生新的內(nèi)存分配

    截圖10.png

    淺拷貝就是對內(nèi)存地址的復(fù)制绩蜻,讓目標(biāo)對象指針和原對象指針指向同一片內(nèi)存空間。
    (b)深拷貝
    特點: 1.深拷貝不會增加被拷貝對象的引用計數(shù) 2.深拷貝產(chǎn)生了內(nèi)存分配
    截圖11.png

    深拷貝讓目標(biāo)對象指針和源對象指針指向兩片內(nèi)容相同的內(nèi)存空間室埋。
    (c)深拷貝vs淺拷貝

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

      copy關(guān)鍵字總結(jié):可變對象的copy和mutableCopy都是深拷貝办绝,不可變對象的copy是淺拷貝,mutableCopy是深拷貝词顾,copy方法返回的都是不可變對象八秃,
      (d)注意點

      @property(copy)NSMutableArray*array 碱妆?
      不論賦值過來的是NSMutableArray 還是NSArray肉盹,copy之后都是NSArray,這樣對array進(jìn)行添加元素或者是刪除元素會導(dǎo)致程序異常。

9.經(jīng)典題目

MRC下如何重寫retain修飾變量的setter方法疹尾?

  @property(nonatomic,retain) id obj;
     - (void)setObjc:(id)obj{
      if(_obj != obj){
          [_obj release];
          [_obj retain];
      }
}

請簡述分類的實現(xiàn)原理上忍?

分類的實現(xiàn)是由運(yùn)行時決議的, 不同分類中含有同名分類方法纳本,誰最終生效取決于誰最后參與編譯窍蓝,最后參與編譯的分類當(dāng)中的同名分類方法會最終生效,如果分類中添加的方法與宿主類方法名相同繁成,分類方法會覆蓋同名的宿主方法吓笙,這里說的覆蓋是指,由于消息傳遞過程中巾腕,優(yōu)先查找數(shù)組靠前的方法面睛,如果找到了一個同名方法就進(jìn)行調(diào)用,實際上宿主類的同名方法是仍然存在尊搬?

KVO實現(xiàn)原理?

能否為分類添加成員變量叁鉴?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市佛寿,隨后出現(xiàn)的幾起案子幌墓,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件常侣,死亡現(xiàn)場離奇詭異蜡饵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)胳施,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門验残,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人巾乳,你說我怎么就攤上這事您没。” “怎么了胆绊?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵氨鹏,是天一觀的道長。 經(jīng)常有香客問我压状,道長仆抵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任种冬,我火速辦了婚禮镣丑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘娱两。我一直安慰自己莺匠,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布十兢。 她就那樣靜靜地躺著趣竣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪旱物。 梳的紋絲不亂的頭發(fā)上遥缕,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機(jī)與錄音宵呛,去河邊找鬼单匣。 笑死,一個胖子當(dāng)著我的面吹牛宝穗,可吹牛的內(nèi)容都是我干的户秤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼讽营,長吁一口氣:“原來是場噩夢啊……” “哼虎忌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起橱鹏,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤膜蠢,失蹤者是張志新(化名)和其女友劉穎堪藐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挑围,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡礁竞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了杉辙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片模捂。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蜘矢,靈堂內(nèi)的尸體忽然破棺而出狂男,到底是詐尸還是另有隱情,我是刑警寧澤品腹,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布岖食,位于F島的核電站,受9級特大地震影響舞吭,放射性物質(zhì)發(fā)生泄漏泡垃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一羡鸥、第九天 我趴在偏房一處隱蔽的房頂上張望蔑穴。 院中可真熱鬧,春花似錦惧浴、人聲如沸存和。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哑姚。三九已至祭饭,卻和暖如春芜茵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背倡蝙。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工九串, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寺鸥。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓猪钮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親胆建。 傳聞我的和親對象是個殘疾皇子烤低,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

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