caregory 和 extension

caregory   (類別)  

不論一個類設計的有多完美,在需求的演繹中總會碰到無法預測的情況,可以動態的爲已有的類添加新行爲

一、caregate主要作用

1 >  爲已知類添加方法

2 >  可以把類的實現部分放在幾個不同的文件裏,減少單個文件的體積;可以把不同功能組織到不同的Category中;可以由多個開發者共同完成一個類

二、Category實現原理

所有OC類和對象在runtime底層都是以結構體表示的,是category_t

typedef struct category_t {

    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;  添加的所有屬性

} category_t;

可以看出category可以添加實例方法、類方法、實現協議、添加屬性、但不能添加實例變量。這裏簡單說一下實例變量、屬性之間的關係

@interface MyViewController :UIViewControlle
{

  UIButton *yourButton;
   int count;
   id data;
}

@property (nonatomic, strong) UIButton *myButton;
@end

實例變量:由類定義的,除去基本數據類型  int、float,,,其他類型的變量都是實例變量

成員變量:代碼中的變量、包括實例變量和基本變量類型,不需要和外界接觸,默認的是protected,一般非子類都無法訪問

屬性:編譯器自動將變量的setter和getter 方法的合成,可以用點語法來讀取,可以爲變量使用,可以與外界接觸

實例變量 +  基本數據類型 =  成員變量

在{ }中聲明的都是成員變量,所以youButton、count、data都是成員變量,實例變量是針對類而言的,成員變量用於類的內部,成員變量不會生成setter和getter方法,爲了方便就有了屬性,屬性的好處是允許其他對象訪問到該變量,因爲屬性的創建自動生成了setter和getter方法

如下:如果聲明瞭實例變量就會報錯

oc的運行時依賴於runtime,加載過程

       拿到編譯器爲我們準備的category的數組,將category的實例方法、協議、屬性添加到類上,把類方法協議方法加到,metaclass上,(category的各種列表添加到類上會調用   addUnattachedCategoryForClass,但他只是一個映射,真正處理事情的是re'methodizeClass,對於添加類方法會調用 attachCategoryMethods方法,他只有把所有的Category實例拼成一個大的實例方法交給attachMethodList方法),然而Category的方法並沒有替換原來的方法,會覆蓋原來的方法,因爲Category的方法被放到了新列表的前面,在運行時查找方法的時候是順着方法列表的順序查找的,只要查找到了對應的名字方法,就會調用

爲什麼Category中 不能添加實例變量?

1、前邊說過,Category本身的定義中沒有實例變量的數組,但在runtime中確實有一個函數:class_addIvar().用來給類添加實例變量,但是這個函數只能在構建一個雷的過程中調用,一旦類完成了定義,就不能再添加成員變量了,類在經過編譯期之後就啓動了runtime,就沒有機會調用addIvar方法了,程序在運行時動態的構建類會調用objc_allocateClasspair之後,但在objc_registerClass之前纔可以被調用,同樣是沒有機會。

2、一塊區域內存包含了所有的成員變量和isa指針,因此在編譯的時候就已經分配好了內存,所以動態的改變了成員變量就改變了這塊內存的佈局

那麼如果一定要才Category中實現添加變量

OC是一門動態的語言,runtime中有兩個函數objc_getAssoctatedObject / objc_setAssoctatdObject 來訪問和生成關聯對象,這兩個方法可以讓一個對象和另一個對象關聯,也就是說一個對象保持對另一個對象的引用,並獲取那個對象

定義一個屬性,重寫setter和getter方法

在setter和getter方法中返回    return  objc_getAssoctatedObject(self,name)    和  objc_setAssoctatedObject(self,nameKey,name,now)

extension  和  Category  比較

extension看起來像一個匿名的Category,但是extension和有名字的Category是兩個不同的東西,extension在編譯期決定,他就是類的一部分,在編譯期將頭文件中的interface和實現裏邊的implement一起形成一個完整的類,一般用來隱藏隱藏類的私有信息,必須要有一個類的源碼才能添加,它伴隨着這個類的產生而產生,消失而消失,因此他可以添加實例變量、屬性、方法,但都是私有方法。

Category是在運行期決定的,他是無法添加實例變量的,在編譯期對象的內存分佈已經確定,如果添加實例變量會破壞類的內存佈局。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章