Objective-C (二)擴(kuò)展與分類(lèi)

分類(lèi)

1.分類(lèi)數(shù)據(jù)結(jié)構(gòu)

  struct objc_category {
      const char *name;
      classref_t cls;
      struct method_list_t *instanceMethods;
      struct method_list_t *classMethods;
      struct protocol_list_t *protocols;
      struct property_list_t *instanceProperties;
      struct property_list_t *_classProperties;

      method_list_t  *methodsForMeta(bool isMeta) {
          if (isMeta) return classMethods;
          else return instanceMethods;
       }  

        property_list_t *propertiesForMeta(bool isMeta , struct header_info *hi);
  }

2.分類(lèi)添加方法的原理:

  • 編譯期過(guò)程
    1. 編譯器生成實(shí)例方法列表OBJC$CATEGORY_INSTANCE_METHODS"className"$"categoryName"和屬性列表OBJC$PROP_LIST"className"$"categoryName"曹傀;用以填充我們?cè)陬?lèi)中定義的方法跟屬性墓塌。
    2. 編譯器生成category本身,并用前面生成的方法列表跟屬性列表初始化category本身
    3. 編譯器在DATA段下的objc_catlist section里保存了一個(gè)大小為1的category_t的數(shù)組L_OBJC_LABELCATEGORY$,用于運(yùn)行期的加載.(關(guān)于DATA段以及以下dyld的內(nèi)容鬼譬,會(huì)在mach-O的篇章介紹)
  • 運(yùn)行期過(guò)程
    1. 拿到catlist上的category_t數(shù)組,把category_t上的實(shí)例方法谚鄙,協(xié)議以及屬性添加到類(lèi)上
    2. 把category_t的類(lèi)方法和協(xié)議添加到類(lèi)的metaclass上
  • 運(yùn)行期添加分類(lèi)過(guò)程
    1. addUnattachedCategoryForClass將類(lèi)和category做一個(gè)映射
    2. remethodizeClass負(fù)責(zé)處理添加事宜
    3. 添加實(shí)例方法會(huì)調(diào)用attachCategoryMethods,它將所有category的實(shí)例方法列表拼成一個(gè)大的實(shí)例方法列表较沪,然后轉(zhuǎn)交給attachMethodList

3.添加屬性
我們都知道無(wú)法給分類(lèi)添加成員變量宣增,因?yàn)閏ategory并不會(huì)為我們生成set,get方法浊吏,這個(gè)時(shí)候可以用關(guān)聯(lián)對(duì)象來(lái)實(shí)現(xiàn)

  objc_setAssociatedObject();
  objc_getAssociatedObject();

關(guān)聯(lián)對(duì)象的原理分析,內(nèi)存管理可看以下章節(jié)

4.load方法與intialize方法的比較

load方法與intialize方法的比較

5.補(bǔ)充的點(diǎn)

  • 分類(lèi)的方法只會(huì)添加救氯,不會(huì)覆蓋原先的方法找田,調(diào)用同名方法時(shí)調(diào)用的是最后編譯的分類(lèi)文件中的方法實(shí)現(xiàn)。
  • intialize方法會(huì)先調(diào)用父類(lèi)着憨,再子類(lèi)墩衙,所以子類(lèi)未實(shí)現(xiàn)時(shí),父類(lèi)會(huì)被多次調(diào)用甲抖。

類(lèi)擴(kuò)展與分類(lèi)區(qū)別

  • 擴(kuò)展可以當(dāng)成一個(gè)匿名的類(lèi)漆改,但是必須要有該類(lèi)的源碼的時(shí)候才能編寫(xiě)擴(kuò)展。(擴(kuò)展不能擁有獨(dú)立的實(shí)現(xiàn)部分)
  • 類(lèi)擴(kuò)展是在編譯期添加到類(lèi)中准谚,而分類(lèi)是在運(yùn)行時(shí)添加
  • 寫(xiě)在.m的類(lèi)擴(kuò)展方法與屬性是私有的

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

  • 關(guān)聯(lián)對(duì)象保存在什么地方

我們先看看函數(shù)_object_set_associative_reference

 void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
    // retain the new value (if any) outside the lock.
    ObjcAssociation old_association(0, nil);
    id new_value = value ? acquireValue(value, policy) : nil;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.associations());
        disguised_ptr_t disguised_object = DISGUISE(object);
        if (new_value) {
            // break any existing association.
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i != associations.end()) {
                // secondary table exists
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    old_association = j->second;
                    j->second = ObjcAssociation(policy, new_value);
                } else {
                    (*refs)[key] = ObjcAssociation(policy, new_value);
                }
            } else {
                // create the new association (first time).
                ObjectAssociationMap *refs = new ObjectAssociationMap;
                associations[disguised_object] = refs;
                (*refs)[key] = ObjcAssociation(policy, new_value);
                _class_setInstancesHaveAssociatedObjects(_object_getClass(object));
            }
        } else {
            // setting the association to nil breaks the association.
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i !=  associations.end()) {
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    old_association = j->second;
                    refs->erase(j);
                }
            }
        }
    }
    // release the old value (outside of the lock).
    if (old_association.hasValue()) ReleaseValue()(old_association);
}
 

從以上代碼可知關(guān)聯(lián)對(duì)象由AssociationsManager管理挫剑,定義如下

class AssociationsManager {
    static OSSpinLock _lock;
    static AssociationsHashMap *_map;               // associative references:  object pointer -> PtrPtrHashMap.
public:
    AssociationsManager()   { OSSpinLockLock(&_lock); }
    ~AssociationsManager()  { OSSpinLockUnlock(&_lock); }
    
    AssociationsHashMap &associations() {
        if (_map == NULL)
            _map = new AssociationsHashMap();
        return *_map;
    }
};

AssociationsManager里面是由一個(gè)靜態(tài)AssociationsHashMap來(lái)存儲(chǔ)所有的關(guān)聯(lián)對(duì)象的。這相當(dāng)于把所有對(duì)象的關(guān)聯(lián)對(duì)象都存在一個(gè)全局map里面柱衔。而map的的key是這個(gè)對(duì)象的指針地址(任意兩個(gè)不同對(duì)象的指針地址一定是不同的)樊破,而這個(gè)map的value又是另外一個(gè)AssociationsHashMap,里面保存了關(guān)聯(lián)對(duì)象的kv對(duì)秀存。

  • 關(guān)聯(lián)對(duì)象的內(nèi)存管理
void *objc_destructInstance(id obj) 
{
    if (obj) {
        Class isa_gen = _object_getClass(obj);
        class_t *isa = newcls(isa_gen);

        // Read all of the flags at once for performance.
        bool cxx = hasCxxStructors(isa);
        bool assoc = !UseGC && _class_instancesHaveAssociatedObjects(isa_gen);

        // This order is important.
        if (cxx) object_cxxDestruct(obj);
        if (assoc) _object_remove_assocations(obj);
        
        if (!UseGC) objc_clear_deallocating(obj);
    }

    return obj;
}

runtime的銷(xiāo)毀對(duì)象函數(shù)objc_destructInstance里面會(huì)判斷這個(gè)對(duì)象有沒(méi)有關(guān)聯(lián)對(duì)象捶码,如果有,會(huì)調(diào)用_object_remove_assocations做關(guān)聯(lián)對(duì)象的清理工作或链。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惫恼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子澳盐,更是在濱河造成了極大的恐慌祈纯,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叼耙,死亡現(xiàn)場(chǎng)離奇詭異腕窥,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)筛婉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)簇爆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)癞松,“玉大人,你說(shuō)我怎么就攤上這事入蛆∠烊兀” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵哨毁,是天一觀的道長(zhǎng)枫甲。 經(jīng)常有香客問(wèn)我,道長(zhǎng)扼褪,這世上最難降的妖魔是什么想幻? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮话浇,結(jié)果婚禮上脏毯,老公的妹妹穿的比我還像新娘。我一直安慰自己凳枝,他們只是感情好抄沮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布跋核。 她就那樣靜靜地躺著岖瑰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪砂代。 梳的紋絲不亂的頭發(fā)上蹋订,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音刻伊,去河邊找鬼露戒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛捶箱,可吹牛的內(nèi)容都是我干的智什。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼丁屎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼荠锭!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起晨川,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤证九,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后共虑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體愧怜,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年妈拌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拥坛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖猜惋,靈堂內(nèi)的尸體忽然破棺而出疾党,到底是詐尸還是另有隱情,我是刑警寧澤惨奕,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布雪位,位于F島的核電站,受9級(jí)特大地震影響梨撞,放射性物質(zhì)發(fā)生泄漏雹洗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一卧波、第九天 我趴在偏房一處隱蔽的房頂上張望时肿。 院中可真熱鬧,春花似錦港粱、人聲如沸螃成。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)寸宏。三九已至,卻和暖如春偿曙,著一層夾襖步出監(jiān)牢的瞬間氮凝,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工望忆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罩阵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓启摄,卻偏偏與公主長(zhǎng)得像稿壁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歉备,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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