Category VS Extension 原理詳解

Category VS Extension 原理詳解

深入理解Objective-C:Category


一: category

categoryObjective-C 2.0之后添加的語言特性,別人口中的 分類、類別其實都是指的category。category的主要作用是為已經(jīng)存在的類添加方法。除此之外,apple還推薦了category的另外兩個使用場景。

1.1: 什么是Category

可以把類的實現(xiàn)分開在幾個不同的文件里面。這樣做有幾個顯而易見的好處。

  • 可以減少單個文件的體積
  • 可以把不同的功能組織到不同的category里
  • 可以由多個開發(fā)者共同完成一個類
  • 可以按需加載想要的category
  • 聲明私有方法

apple的SDK中就大面積的使用了category這一特性。比如UIKit中的UIView。apple把不同的功能API進行了分類,這些分類包括UIViewGeometry、UIViewHierarchy、UIViewRendering等。

不過除了apple推薦的使用場景,廣大開發(fā)者腦洞大開,還衍生出了category的其他幾個使用場景:

  • 模擬多繼承(另外可以模擬多繼承的還有protocol)
  • 把framework的私有方法公開
1.2: category特點
  • category只能給某個已有的類擴充方法,不能擴充成員變量。
  • category中也可以添加屬性,只不過@property只會生成settergetter的聲明,不會生成settergetter的實現(xiàn)以及成員變量。
  • 如果category中的方法和類中原有方法同名,運行時會優(yōu)先調(diào)用category中的方法。也就是,category中的方法會覆蓋掉類中原有的方法。所以開發(fā)中盡量保證不要讓分類中的方法和原有類中的方法名相同。避免出現(xiàn)這種情況的解決方案是給分類的方法名統(tǒng)一添加前綴。比如category_。
  • 如果多個category中存在同名的方法,運行時到底調(diào)用哪個方法由編譯器決定,最后一個參與編譯的方法會被調(diào)用。

如下圖,給UIView添加了兩個categoryonetwo),并且給這兩個分類都添加了名為log的方法:

UIView+one
UIView+two

在viewController中引入這兩個category的.h文件。調(diào)用log方法:

調(diào)用category方法

當(dāng)編譯順序如下圖所示時,調(diào)用UIView + one.m的log方法,如下圖:

編譯順序

調(diào)用結(jié)果

UIView + one.m移動到UIView + two.m上面,調(diào)用UIView + two.m的log方法,如下圖:

編譯順序
調(diào)用結(jié)果
1.3: 調(diào)用優(yōu)先級

分類(category) > 本類 > 父類。即,優(yōu)先調(diào)用cateory中的方法,然后調(diào)用本類方法,最后調(diào)用父類方法。

注意:category是在運行時加載的,不是在編譯時。

1.4: 為什么category不能添加成員變量?

Objective-C類是由Class類型來表示的,它實際上是一個指向objc_class結(jié)構(gòu)體的指針。它的定義如下:

typedef struct objc_class *Class;

objc_class結(jié)構(gòu)體的定義如下:

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;  // 父類
    const char *name                        OBJC2_UNAVAILABLE;  // 類名
    long version                            OBJC2_UNAVAILABLE;  // 類的版本信息,默認為0
    long info                               OBJC2_UNAVAILABLE;  // 類信息,供運行期使用的一些位標(biāo)識
    long instance_size                      OBJC2_UNAVAILABLE;  // 該類的實例變量大小
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 該類的成員變量鏈表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定義的鏈表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法緩存
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 協(xié)議鏈表
#endif
} OBJC2_UNAVAILABLE;

在上面的objc_class結(jié)構(gòu)體中,ivarsobjc_ivar_list(成員變量列表)指針;methodLists是指向objc_method_list指針的指針。在Runtime中,objc_class結(jié)構(gòu)體大小是固定的,不可能往這個結(jié)構(gòu)體中添加數(shù)據(jù),只能修改。所以ivars指向的是一個固定區(qū)域,只能修改成員變量值,不能增加成員變量個數(shù)。methodList是一個二維數(shù)組,所以可以修改*methodLists的值來增加成員方法,雖沒辦法擴展methodLists指向的內(nèi)存區(qū)域,卻可以改變這個內(nèi)存區(qū)域的值(存儲的是指針)。因此,可以動態(tài)添加方法,不能添加成員變量。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,058評論 0 9
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,892評論 33 466
  • 一、Runtime簡介 Runtime簡稱運行時。OC就是運行時機制,也就是在運行時候的一些機制,其中最主要的是消...
    林安530閱讀 1,112評論 0 2
  • 對于從事 iOS 開發(fā)人員來說,所有的人都會答出【runtime 是運行時】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,812評論 7 64
  • 下午放學(xué)后,一般會在學(xué)校待一會兒,玩一些游戲,晚上安排自習(xí)之后更是如此,直到快吃晚飯的時候才會回家。 這個時候開始...
    哇_哦閱讀 135評論 0 3

友情鏈接更多精彩內(nèi)容