Objective-C中的實(shí)例方法、類方法掂器、Category亚皂、Protocol

1.方法

Objective-C中的方法有兩種:

1.1 實(shí)例方法

-開(kāi)頭的方法是實(shí)例方法。它屬于類的某一個(gè)或某幾個(gè)實(shí)例對(duì)象国瓮,即類對(duì)象必須實(shí)例化后才可以使用的方法灭必,將消息發(fā)送給實(shí)例對(duì)象:

// Deck.h

#import <Foundation/Foundation.h>
#import "Card.h"

@interface Deck : NSObject

@property(nonatomic) int cardNum;

// 實(shí)例方法
- (Card *)randomDrawCard;

+ (NSString *)CardKinds;

@end

實(shí)例方法中可以使用該類的所有實(shí)例變量:

// Deck.m

#import "Card.h"

@implementation Deck

- (Card *)drawCardFromTop
{
    // 實(shí)例變量
    _cardNum--;

    //TODO.....
}

+ (NSString *)CardKinds
{
    NSLog("Cards are divided into four kinds: spades, diamonds, clubs and hearts");
}

@end 

1.2 類方法

+開(kāi)頭的方法是類方法。Objc中的類方法類似Java中的static靜態(tài)方法乃摹,它是屬于類本身的方法厂财,不屬于類的某一個(gè)實(shí)例對(duì)象,所以不需要實(shí)例化類峡懈,用類名即可使用璃饱,是將消息發(fā)送給類:

// Deck.h

#import <Foundation/Foundation.h>
#import "Card.h"

@interface Deck : NSObject

- (Card *)randomDrawCard;

// 類方法
+ (NSString *)CardKinds;

@end    

類方法不能使用任何實(shí)例變量:

// Deck.m

#import "Card.h"

@implementation Deck

- (Card *)drawCardFromTop
{
    // 實(shí)例變量
    _cardNum--;

    //TODO.....
}

// 不能使用該類的實(shí)例變量_carNum
+ (NSString *)CardKinds
{
    NSLog("Cards are divided into four kinds: spades, diamonds, clubs and hearts");
}

@end 

所以我們使用類方法一般有兩種情況:

  • 創(chuàng)建一些事物,比如特殊格式的字符串等肪康。
  • 作為工具方法荚恶,比如返回常數(shù)等。

1.3 類方法和實(shí)例方法認(rèn)知的誤區(qū)

  • 類方法常駐內(nèi)存磷支,所以比實(shí)例方法效率高谒撼。
    事實(shí)上,在加載時(shí)機(jī)和占用內(nèi)存上雾狈,類方法和實(shí)例方法是一樣的廓潜,在類第一次被使用時(shí)加載方法,所以在效率上沒(méi)有什么區(qū)別。

  • 類方法分配在堆上辩蛋,實(shí)例方法分配在棧上呻畸。
    事實(shí)上,所有的方法都不可能分配在堆棧區(qū)悼院,方法作為二進(jìn)制代碼是存儲(chǔ)在內(nèi)存的程序代碼區(qū)伤为,這個(gè)內(nèi)存區(qū)域是不可寫(xiě)的。請(qǐng)查看我這篇筆記中的相關(guān)概念Objective-C中的Block据途。

1.4 總結(jié)

實(shí)例方法和類方法有大多數(shù)的共性绞愚,比如都可以有一個(gè)或多個(gè)參數(shù)、都可以繼承基類的方法颖医、相同的聲明規(guī)范等位衩。唯一不同的就是類方法不能使用實(shí)例變量,所以導(dǎo)致它只適用于一些特殊的情況熔萧。

2.Category

如果我們想給一個(gè)已存在的蚂四、很復(fù)雜的類添加一個(gè)新的方法,應(yīng)該怎么做哪痰?
想翻源碼添加遂赠?騷年,你太天真晌杰,你如果看不到源碼呢跷睦。即便我們可以看到源碼,如果我們新增的邏輯也很復(fù)雜肋演,這樣就會(huì)擴(kuò)大原始設(shè)計(jì)的規(guī)模抑诸,有可能會(huì)打亂整個(gè)設(shè)計(jì)的結(jié)構(gòu)。
Category就是Objective-C提供的為我們解決這一問(wèn)題的方法爹殊。它可以讓我們動(dòng)態(tài)的在已經(jīng)存在的類中添加新的行為蜕乡,即方法。對(duì)類進(jìn)行擴(kuò)展時(shí)不需要訪問(wèn)其源碼梗夸,也不需要?jiǎng)?chuàng)建子類层玲。

2.1 使用方法

Category的實(shí)現(xiàn)很簡(jiǎn)單,我們舉例說(shuō)明反症。

// Deck.h

#import <Foundation/Foundation.h>
#import "Card.h"

@interface Deck : NSObject

- (Card *)randomDrawCard;

@end

這是類Deck的聲明文件辛块,其中包含一個(gè)實(shí)例方法randomDrawCard,如果我們想在不修改原始類铅碍、不增加子類的情況下润绵,為該類增加一個(gè)drawCardFromTop方法,只需要定義兩個(gè)文件Deck+DrawCardFromTop.hDeck+DrawCardFromTop.m胞谈,在聲明文件和實(shí)現(xiàn)文件中用()把Category的名稱括起來(lái)即可尘盼,聲明文件如下:

// Deck+DrawCardFromTop.h

#import "Deck.h"
#import "Card.h"

@interface Deck(DrawCardFromTop)

- (Card *)drawCardFromTop;

@end

實(shí)現(xiàn)文件如下:

// Deck+DrawCardFromTop.m

#import "Deck+DrawCardFromTop.h"
#import "Card.h"

@implementation Deck(DrawCardFromTop)

- (Card *)drawCardFromTop
{
    //TODO.....
}

@end

DrawCardFromTop是Category的名稱憨愉。這里一般使用約定俗成的習(xí)慣,將聲明文件和實(shí)現(xiàn)文件統(tǒng)一采用"原類名+Category名"的方式命名卿捎。
使用也非常簡(jiǎn)單配紫,引入Category的聲明文件,然后正常調(diào)用即可:

// main.m

#import "Deck+DrawCardFromTop.h"
#import "Card.h"

int main(int argc, char * argv[])
{

    Deck *deck = [[Deck alloc] init];
    Card *card = [deck drawCardFromTop];

    return 0;

}

2.2 使用場(chǎng)景

  • 需求變更在整個(gè)開(kāi)發(fā)周期是司空見(jiàn)慣的事情娇澎,那么我們可能就需要對(duì)某個(gè)或某幾個(gè)類中添加新的方法以滿足需求笨蚁。
  • 我們?cè)趫F(tuán)隊(duì)協(xié)作開(kāi)發(fā)時(shí)候睹晒,經(jīng)常需要多個(gè)人來(lái)實(shí)現(xiàn)一個(gè)類中的不同方法趟庄,在這種情況下采用Category是一個(gè)較好的選擇。
  • 當(dāng)一些基礎(chǔ)類庫(kù)滿足不了我們的需求時(shí)伪很,我們希望能擴(kuò)展基礎(chǔ)類庫(kù)戚啥,這時(shí)就需要Category。

2.3 需要注意的問(wèn)題

  • Category可以訪問(wèn)原始類的實(shí)例變量锉试,但不能添加變量猫十,如果想添加變量,可以考慮通過(guò)繼承創(chuàng)建子類呆盖。
  • Category可以重載原始類的方法拖云,但不推薦這么做,這么做的后果是你再也不能訪問(wèn)原來(lái)的方法应又。如果確實(shí)要重載宙项,正確的選擇是創(chuàng)建子類。
  • 和普通接口有所區(qū)別的是株扛,在分類的實(shí)現(xiàn)文件中可以不必實(shí)現(xiàn)所有聲明的方法尤筐,只要你不去調(diào)用它。

2.4 總結(jié)

掌握并用好Category可以充分利用Objective-C的動(dòng)態(tài)特性洞就,編寫(xiě)出靈活簡(jiǎn)潔的代碼盆繁。

3.Protocol

簡(jiǎn)單來(lái)說(shuō),Protocol不屬于任何一個(gè)類旬蟋,它只是一個(gè)方法列表油昂,任何類都可以對(duì)其中聲明的方法進(jìn)行實(shí)現(xiàn)。這種設(shè)計(jì)模式一般稱為代理模式(delegation)倾贰。你可以通過(guò)Protocol定義各種行為秕狰,在不同的場(chǎng)景采用不同的實(shí)現(xiàn)方式。在iOS和OS X開(kāi)發(fā)中躁染,Apple采用了大量的代理模式來(lái)實(shí)現(xiàn)MVC中View和Controller的解耦鸣哀。

3.1 使用方法

Protocol有兩種聲明的方式:

  • 在單獨(dú)的聲明文件(.h文件)中聲明。
  • 在某個(gè)類的聲明的文件中聲明吞彤。

以上兩種方式視具體情況而定我衬,但是在代碼規(guī)范上都是一致的:

// HandleDeckDelegate.h

@protocol HandleDeckDelegate <NSObject>

@required
- (void)ShuffleDeck;

@optional
- (void)CuttingDeck;

@end

上述代碼中有兩個(gè)關(guān)鍵字叹放,@required@optional,表示如果要實(shí)現(xiàn)這個(gè)協(xié)議挠羔,那么ShuffleDeck方法是必須要實(shí)現(xiàn)的傲武,CuttingDeck則是可選的,如果不注明囊拜,那么方法默認(rèn)是@required的兔港,必須實(shí)現(xiàn)。

那么如何實(shí)現(xiàn)這個(gè)Protocol呢范舀,很簡(jiǎn)單合是,創(chuàng)建一個(gè)普通的Objective-C類,如果Protocol使用單獨(dú)的.h文件聲明锭环,那么在該類的.h聲明文件中引入包含Protocol的.h文件聪全,如果Protocol是聲明在一個(gè)相關(guān)類中,那么就需要引入該類的.h文件辅辩。之后聲明采用這個(gè)Protocol即可:

// Deck.h

#import <Foundation/Foundation.h>
#import "Card.h"
#import "HandleDeckDelegate.h"

@interface Deck : NSObject<HandleDeckDelegate>

- (Card *)randomDrawCard;

@end

用尖括號(hào)(<...>)括起來(lái)的HandleDeckDelegate就是我們創(chuàng)建的Protocol难礼。如果要采用多個(gè)Protocol,可以在尖括號(hào)內(nèi)引入多個(gè)Protocol名稱玫锋,并用逗號(hào)隔開(kāi)即可蛾茉。例如<HandleDeckDelegate,xxxDelegate>

// Deck.m

#import "Card.h"

@implementation Deck

- (Card *)drawCardFromTop
{
    //TODO.....
}

- (void)ShuffleDeck
{
    //TODO.....
}

@end

由于CuttingDeck方法是可選的撩鹿,所以我們只實(shí)現(xiàn)了ShuffleDeck谦炬。

3.2 使用場(chǎng)景

  • Objective-C里的Protocol和Java語(yǔ)言中的接口很類似,如果一些類之間沒(méi)有繼承關(guān)系三痰,但是又具備某些相同的行為吧寺,則可以使用Protocol來(lái)描述它們的關(guān)系。
  • 不同的類散劫,可以遵守同一個(gè)Protocol稚机,在不同的場(chǎng)景下注入不同的實(shí)例,實(shí)現(xiàn)不同的功能获搏。

3.3 需要注意的問(wèn)題

  • 根據(jù)約定赖条,框架中后綴為Delegate的都是Protocol,例如UIApplicationDelegate常熙,UIWebViewDelegate等纬乍。
  • Protocol本身是可以繼承的,比如:
@protocol A
    -(void)methodA;
@end

@protocol B <A>
    -(void)methodB;
@end

如果你要實(shí)現(xiàn)B裸卫,那么methodA和methodB都需要實(shí)現(xiàn)仿贬。

  • Protocol是與任何類都無(wú)關(guān)的,任何類都可以實(shí)現(xiàn)定義好的Protocol墓贿,如果我們想知道某個(gè)類是否實(shí)現(xiàn)了某個(gè)Protocol茧泪,那么我們可以用conformsToProtocol方法進(jìn)行判斷:
[obj conformsToProtocol:@protocol(ProcessDataDelegate)] 

3.4 總結(jié)

Protocol最常用的就是委托代理模式蜓氨,Cocoa框架中大量采用了這種模式實(shí)現(xiàn)數(shù)據(jù)和UI的分離。例如UIView產(chǎn)生的所有事件队伟,都是通過(guò)委托的方式交給Controller完成穴吹。

本文首發(fā)地址:Objective-C中的實(shí)例方法、類方法嗜侮、Category港令、Protocol

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锈颗,隨后出現(xiàn)的幾起案子顷霹,更是在濱河造成了極大的恐慌,老刑警劉巖宜猜,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泼返,死亡現(xiàn)場(chǎng)離奇詭異硝逢,居然都是意外死亡姨拥,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)渠鸽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)叫乌,“玉大人,你說(shuō)我怎么就攤上這事徽缚『┘椋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵凿试,是天一觀的道長(zhǎng)排宰。 經(jīng)常有香客問(wèn)我,道長(zhǎng)那婉,這世上最難降的妖魔是什么板甘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮详炬,結(jié)果婚禮上盐类,老公的妹妹穿的比我還像新娘。我一直安慰自己呛谜,他們只是感情好在跳,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著隐岛,像睡著了一般猫妙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上聚凹,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天割坠,我揣著相機(jī)與錄音逻悠,去河邊找鬼。 笑死韭脊,一個(gè)胖子當(dāng)著我的面吹牛童谒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沪羔,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼饥伊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蔫饰?” 一聲冷哼從身側(cè)響起琅豆,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎篓吁,沒(méi)想到半個(gè)月后茫因,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杖剪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年冻押,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盛嘿。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洛巢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出次兆,到底是詐尸還是另有隱情稿茉,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布芥炭,位于F島的核電站漓库,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏园蝠。R本人自食惡果不足惜渺蒿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望砰琢。 院中可真熱鬧蘸嘶,春花似錦、人聲如沸陪汽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)挚冤。三九已至况增,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間训挡,已是汗流浹背澳骤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工歧强, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人为肮。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓摊册,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親颊艳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子茅特,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

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