iOS Objective-C 類(lèi)擴(kuò)展

iOS Objective-C 類(lèi)擴(kuò)展

1. 類(lèi)擴(kuò)展簡(jiǎn)介

類(lèi)擴(kuò)展是我們?cè)陂_(kāi)發(fā)中經(jīng)常忽略的一個(gè)知識(shí)點(diǎn)乏梁。就我個(gè)人來(lái)說(shuō),一直認(rèn)為類(lèi)擴(kuò)展就是類(lèi)中的一部分律姨,我們主要在其中聲明私有屬性米苹,其實(shí)不是,因?yàn)轭?lèi)擴(kuò)展是單獨(dú)存在的忍啸,我們新建一個(gè)類(lèi)的時(shí)候并不會(huì)主動(dòng)創(chuàng)建類(lèi)擴(kuò)展仰坦。但也是,因?yàn)轭?lèi)擴(kuò)展在類(lèi)編譯的時(shí)候一起編譯计雌。

類(lèi)擴(kuò)展的定義:

A class extension bears some similarity to a category, but it can only be added to a class for which you have the source code at compile time (the class is compiled at the same time as the class extension). The methods declared by a class extension are implemented in the @implementation block for the original class so you can’t, for example, declare a class extension on a framework class, such as a Cocoa or Cocoa Touch class like NSString.

譯:類(lèi)擴(kuò)展與分類(lèi)有一些相似之處悄晃,但它只能添加到在編譯時(shí)擁有源代碼的類(lèi)中(類(lèi)與類(lèi)擴(kuò)展同時(shí)編譯)。類(lèi)擴(kuò)展聲明的方法是在原始類(lèi)的@implementation塊中實(shí)現(xiàn)的白粉,所以你不能在框架類(lèi)上聲明類(lèi)擴(kuò)展传泊,比如Cocoa或Cocoa Touch類(lèi),比如NSString鸭巴。

類(lèi)擴(kuò)展的聲明語(yǔ)法:

@interface ClassName ()
 
@end

新建一個(gè)類(lèi)擴(kuò)展:

我們?cè)?code>Xcode中創(chuàng)建Objective類(lèi)型的文件的時(shí)候可以選擇空文件眷细、分類(lèi)、協(xié)議以及類(lèi)擴(kuò)展鹃祖。

新建類(lèi)擴(kuò)展.jpg

雖然Xcode給我們提供了新建類(lèi)擴(kuò)展的選項(xiàng)溪椎,但是一般我們不這樣用,我們一般都是在.m文件中聲明一下當(dāng)前的類(lèi)擴(kuò)展恬口,其實(shí)協(xié)議的聲明我們大多數(shù)也是這樣做的校读。

2. 類(lèi)拓展的應(yīng)用

2.1 添加屬性

@interface XYZPerson ()
@property NSObject *extraProperty;
@end

2.2 添加實(shí)例變量

添加自定義實(shí)例變量。需要在類(lèi)擴(kuò)展接口的大括號(hào)中聲明祖能。

@interface XYZPerson () {
    id _someCustomInstanceVariable;
}
@end

2.3 隱藏私有信息

在類(lèi)中聲明一個(gè)只讀的屬性uniqueIdentifier如下歉秫,這樣我們暴露給外界的時(shí)候就是只讀的。

@interface XYZPerson : NSObject
...
@property (readonly) NSString *uniqueIdentifier;
- (void)assignUniqueIdentifier;
@end

但是我們想在類(lèi)內(nèi)部進(jìn)行更改就可以通過(guò)類(lèi)擴(kuò)展來(lái)實(shí)現(xiàn)养铸,如下

@interface XYZPerson ()
@property (readwrite) NSString *uniqueIdentifier;
@end
 
@implementation XYZPerson
...
@end

3. 驗(yàn)證類(lèi)擴(kuò)展的確定時(shí)機(jī)是編譯時(shí)

我們新建一個(gè)LGPerson類(lèi)雁芙,并新建一個(gè)LGPerson+Extension的類(lèi)擴(kuò)展轧膘。代碼如下:

LGPerson 代碼:


#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
@end

NS_ASSUME_NONNULL_END


#import "LGPerson.h"
#import "LGPerson+Extension.h"

@interface LGPerson ()
@property (nonatomic, copy) NSString *mName;

- (void)extM_method;
@end

@implementation LGPerson

+ (void)load{
    NSLog(@"%s",__func__);
}

- (void)extM_method{
    NSLog(@"%s",__func__);
}

- (void)extH_method{
    NSLog(@"%s",__func__);
}

@end

LGPerson+Extension 代碼:

#import "LGPerson.h"


NS_ASSUME_NONNULL_BEGIN

@interface LGPerson ()
@property (nonatomic, copy) NSString *ext_name;
@property (nonatomic, copy) NSString *ext_subject;

- (void)extH_method;
@end

NS_ASSUME_NONNULL_END

main.m 代碼:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "LGPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        
        LGPerson *p = [LGPerson alloc];
        NSLog(@"%@ - %p", p, p);
        
    }
    return 0;
}

先導(dǎo)知識(shí),類(lèi)中由編譯器確定的實(shí)例方法以及屬性存儲(chǔ)在類(lèi)的bits->data->ro中兔甘,我們只要驗(yàn)證在ro中存在我們?cè)谏厦娲a中定義的方法和屬性以及屬性的settergetter方法就可以說(shuō)明類(lèi)擴(kuò)展的確定時(shí)機(jī)是類(lèi)編譯的時(shí)候谎碍。先導(dǎo)知識(shí)傳送門(mén):
iOS Objective-C 類(lèi)原理
iOS Objective-C 方法的本質(zhì)

lldb.jpg

通過(guò)上面這幅圖,我們已經(jīng)在robaseProperties中找到了我們類(lèi)中已經(jīng)類(lèi)擴(kuò)展中的所有屬性洞焙,以及在baseMethodList找到了我們類(lèi)中和類(lèi)擴(kuò)展中的方法已經(jīng)屬性的gettersetter方法蟆淀,至此我們已經(jīng)驗(yàn)證了類(lèi)擴(kuò)展的確定時(shí)機(jī)是在編譯期。

但是有一點(diǎn)值得注意澡匪,如果我們沒(méi)有在類(lèi)的頭文件或者源文件中引入單獨(dú)的類(lèi)拓展頭文件熔任,那么這個(gè)單獨(dú)的類(lèi)拓展的頭文件里面的屬性和方法將不會(huì)被加載到類(lèi)上面來(lái)。會(huì)認(rèn)為你不用唁情,優(yōu)化掉了笋敞。

4. 類(lèi)擴(kuò)展和分類(lèi)的區(qū)別

按照官方的文檔的說(shuō)法,類(lèi)擴(kuò)展與分類(lèi)很相似荠瘪,也可以說(shuō)是匿名的分類(lèi)但是它們之間也有很多的區(qū)別夯巷。iOS Objective-C 分類(lèi)的加載

操作對(duì)象 是否有implementation 加載時(shí)機(jī) 操作對(duì)象 能否通過(guò)@property聲明屬性生成 getter 和 setter
類(lèi)擴(kuò)展 無(wú) 編譯時(shí) ro 可以
分類(lèi) 運(yùn)行時(shí)/編譯時(shí) ro/rw 不可以,需要借助關(guān)聯(lián)對(duì)象

5. 參考資料

Customizing Existing Classes

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哀墓,一起剝皮案震驚了整個(gè)濱河市趁餐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌篮绰,老刑警劉巖后雷,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異吠各,居然都是意外死亡臀突,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)贾漏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)候学,“玉大人,你說(shuō)我怎么就攤上這事纵散∈崧耄” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵伍掀,是天一觀(guān)的道長(zhǎng)掰茶。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蜜笤,這世上最難降的妖魔是什么濒蒋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮把兔,結(jié)果婚禮上沪伙,老公的妹妹穿的比我還像新娘甸各。我一直安慰自己,他們只是感情好焰坪,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著聘惦,像睡著了一般某饰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上善绎,一...
    開(kāi)封第一講書(shū)人閱讀 49,850評(píng)論 1 290
  • 那天黔漂,我揣著相機(jī)與錄音,去河邊找鬼禀酱。 笑死炬守,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的剂跟。 我是一名探鬼主播减途,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼曹洽!你這毒婦竟也來(lái)了鳍置?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤送淆,失蹤者是張志新(化名)和其女友劉穎税产,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體偷崩,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辟拷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阐斜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衫冻。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖谒出,靈堂內(nèi)的尸體忽然破棺而出羽杰,到底是詐尸還是另有隱情,我是刑警寧澤到推,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布考赛,位于F島的核電站,受9級(jí)特大地震影響莉测,放射性物質(zhì)發(fā)生泄漏颜骤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一捣卤、第九天 我趴在偏房一處隱蔽的房頂上張望忍抽。 院中可真熱鬧八孝,春花似錦、人聲如沸鸠项。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)祟绊。三九已至楼入,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間牧抽,已是汗流浹背嘉熊。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扬舒,地道東北人阐肤。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像讲坎,于是被迫代替她去往敵國(guó)和親孕惜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349