Objective-C中的類目(Category),延展(Extension),協議(Protocol)這些名詞看起來挺牛的,瞬間感覺OC好高大上。在其他OOP語言中就沒見過這些名詞,剛看到這三個名詞的時候,有種感覺這是不是學習的坎?這東西難不難?能不能學會?經過本人親自驗證,這三個東西理解起來還是蠻簡單的,學過C++或者Java的小夥伴對比理解還是蠻輕鬆的。類目(Category)就是給已有的類擴充相應的方法,擴充的方法是公有的,類目還可以起到分模組的功能,下面會詳細說到。 延展(Extension)這個名詞就是是匿名類目的別稱,匿名類目就叫做延展,延展可以實現類方法的私有化,具體如何實現,下面有原始碼。協議我個人感覺和Java中的介面極為相似,在定義物件時使用協議,個人感覺和Java中得泛型有著異曲同工之妙,看下文的詳細介紹吧。(本文為筆者個人總結,歡迎批評指正)。
一.Objective-C中的類目(Category)
在Objective-C比其他OOP的程式語言多了個類目,在OC中除了用繼承來擴充類的功能函式外我們還可以用類目來實現。學過C++的小夥伴們是否還記得友元這個概念呢?友元就是非本類的方法可以使用本類中得變數,這也是對類方法的一個擴充,個人感覺在OC中得類目和C++中的友元有著異曲同工之妙(僅代表個人觀點,歡迎批評指正),下面我們就來詳細的學習一下OC中得類目吧。
提到類目呢,首先我們會問我們具體能拿類目做些什麼事情呢下面做一下總結:
1.可以用類目給已有的類擴充方法
2.可以用類目把類的實現按功能模組分為不同的檔案
3.可以用來擴充套件NSObject類的方法,也叫做非正式協議
編譯環境說明: iMac OS X 10.9 (13A603) 編譯器:XCode 5.0.2版本
1.給已有的類擴充方法
在Xcode中新建CategoryTest類,在新建類中宣告兩個例項變數,在實現類中重寫description方法,列印輸出兩個例項變數的值
程式碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//CategoryTest.h #import @interface CategoryTest : NSObject //定義兩個私有的屬性 { @private int ludashi1; int ludashi2; } @end //CategoryTest.m #import "CategoryTest.h" @implementation CategoryTest //重寫description方法 -(NSString *) description { return [NSString stringWithFormat:@"ludashi1 = %d, ludashi2 = %d", ludashi1,ludashi2]; } @end |
新建一個CategoryTest的類目,來進行對類方法的擴充,
程式碼如下:
1 2 3 4 5 6 7 8 9 |
// CategoryTest+CategoryExtendFunction.h // Memory // Created by ludashi on 14-8-4. // Copyright (c) 2014年 Mr.li. All rights reserved. #import "CategoryTest.h" @interface CategoryTest (CategoryExtendFunction) //利用類目擴充套件新的方法 -(void) extendFunction; @end |
實現檔案:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// // CategoryTest+CategoryExtendFunction.m // Memory // Created by ludashi on 14-8-4. // Copyright (c) 2014年 Mr.li. All rights reserved. #import "CategoryTest+CategoryExtendFunction.h" @implementation CategoryTest (CategoryExtendFunction) //實現擴充套件的方法 -(void)extendFunction { NSLog(@"魯大師,你好!我是通過類目擴充套件的方法!"); } @end |
測試執行結果:
1 |
2014-08-04 17:08:46.187 Memory[1621:303] 魯大師,你好!我是通過類目擴充套件的方法! |
2.對把類中不同的功能模組分成不同的檔案
1.給上面的類建立兩個類目,類目中分別存放例項變數的getter和setter方法,為了節省篇幅下面給出其中一個類目的事例;
介面的宣告:
1 2 3 4 5 6 7 8 9 10 11 |
// CategoryTest+Categgory1.h // Memory // Created by ludashi on 14-8-4. // Copyright (c) 2014年 Mr.li. All rights reserved. #import "CategoryTest.h" @interface CategoryTest (Categgory1) //宣告Category中例項變數ludashi1的getter和setter方法 -(void) setLudashi1:(int) vLudashi; -(int) ludashi1; @end |
類目的實現檔案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// CategoryTest+Categgory1.m // Memory // Created by ludashi on 14-8-4. // Copyright (c) 2014年 Mr.li. All rights reserved. #import "CategoryTest+Category1.h" @implementation CategoryTest (Categgory1) //實現ludashi1的getter和setter方法 -(void)setLudashi1:(int)vLudashi { ludashi1 = vLudashi; } //getter方法 -(int) ludashi1 { return ludashi1; } @end |
對程式碼測試的結果:
1 |
2014-08-04 17:08:46.188 Memory[1621:303] ludashi1 = 10, ludashi2 = 20 |
3.非正式協議
非正式協議就是給NSObject類建立的類目又叫做非正式協議, 非正式協議一般不需要進行實現,一般在子類中進行方法的重寫。程式碼在這就不贅述啦!
類目的優缺點分析(下面有些是個人觀點,不對之處請批評指正)
優點:上面的功能也是類目存在的重要原因之所在,在這就不重複了
侷限性: 在類目中只可以為類新增方法,不能新增例項變數; 類目中得方法的優先順序要高。
二.Objective-C中的延展(Extension)
簡單的說匿名類目就是延展,在延展中定義的方法是類私有的方法只能在類的內部呼叫,定義延展的方式就是把類目中括號中得名字省略掉,括號保留這就是延展。其實在延展中定義的方法不是真正的私有方法和C++, Java中得方法還有所區別,在類初始化的檔案中引入相應延展的標頭檔案,其延展對應的方法也是可以訪問的。是通過隱藏延展的標頭檔案來達到方法私有 的。
定義私有方法有以下三種方式:
1.通過延展來實現方法的私有,延展的標頭檔案獨立。這種方法不能實現真正的方法私有,當在別的檔案中引入延展的標頭檔案,那麼在這個檔案中定義的類的物件就可以直接呼叫在延展中定義所謂私有的方法。demo如下:
程式碼如下:
延展相應的標頭檔案,延展方法的實現在類對應的.m中給出實現方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#import "ExtensionTest.h" @interface ExtensionTest () -(void)privateFunction1; @end</pre〉 2.第二種實現延展的方式是延展沒有獨立的標頭檔案,在類的實現檔案.m中宣告和實現延展,這種方法可以很好的實現方法的私有,因為在OC中是不能引入.m的檔案的 3.第三種實現方法私有的方式是在.m檔案中得@implementation中直接實現在@interface中沒有宣告的方法,這樣也可以很好的實現方法的私有。 Extension.m中的程式碼 <pre class="lang:objc decode:true ">#import "ExtensionTest.h" #import "ExtensionTest_Extension1.h" //在實現方法裡宣告延展 @interface ExtensionTest() -(void) privateFunction2; @end @implementation ExtensionTest //實現各種方法 -(void)publicFunction { NSLog(@"publicFunction PS:我是正兒八經的公用方法,我在.h中被宣告,在.m中被實現"); //呼叫各種私有方法 [self privateFunction1]; [self privateFunction2]; [self privateFunction3]; } //實現第一個私有方法(第一種實現類方法私有化的方法) -(void)privateFunction1 { NSLog(@"PrivateFunction1 PS:我是在別的標頭檔案中定義的延展,在.m中被實現"); } //實現第二個私有方法(第二種實現類方法私有化的方法) -(void)privateFunction2 { NSLog(@"PrivateFunction2 PS:我是在本檔案中定義的延展,在本檔案中進行實現!"); } //在標頭檔案中為宣告的方法在.m中直接定義是私有的方法 -(void)privateFunction3 { NSLog(@"PrivateFunction3: 我是在實現方法中直接定義的方法,我也是私有變數"); } end |
在main函式裡進行測試,如果在main函式裡引入#import “ExtensionTest_Extension1.h”也可以呼叫其裡面宣告的相應的方法
測試程式碼如下:
1 2 3 4 |
//測試延展 ExtensionTest *extension = [ExtensionTest new]; [extension publicFunction]; [extension privateFunction1]; |
執行結果:
1 2 3 4 5 |
2014-08-05 15:54:46.147 Memory[1683:303] publicFunction PS:我是正兒八經的公用方法,我在.h中被宣告,在.m中被實現 2014-08-05 15:54:46.149 Memory[1683:303] PrivateFunction1 PS:我是在別的標頭檔案中定義的延展,在.m中被實現 2014-08-05 15:54:46.149 Memory[1683:303] PrivateFunction2 PS:我是在本檔案中定義的延展,在本檔案中進行實現! 2014-08-05 15:54:46.150 Memory[1683:303] PrivateFunction3: 我是在實現方法中直接定義的方法,我也是私有變數 2014-08-05 15:54:46.150 Memory[1683:303] PrivateFunction1 PS:我是在別的標頭檔案中定義的延展,在.m中被實現 |
三、Objective中得協議Protocol
協議(protocol)提到OC中得協議個人感覺和JAVA中的介面的用法極為相似。把類中常用的方法抽象成OC中得協議,協議中只有方法的宣告沒有方法的實現,在protocol中可以把方法定義成@required(必須的):在使用協議的類中如果不實現@required的方法,編譯器不會報錯但會給出警告。還可以把protocol中的方法定義成@optional(可選的)如果在使用協議的類中不實現@optional方法,則不會警告。協議的關鍵字用@protocol來定義。
下面是協議的一個簡單demo;
1.在Xcode中新建一個Protocol,命名為FirstProtocol,檔名為FirstProtocol.h . 在FirstProtocol協議中宣告瞭兩個方法,一個是@required一個是@optional的
1 2 3 4 5 6 7 8 9 10 11 12 |
#import //建立第一個protocol @protocol FirstProtocol //為protocol里加入必須實現的方法 @required -(void)requiredFunction; //定義可選的方法 @optional -(void)optionalFunction; @end |
2.新建一個類命名為ProtocolClass, 在ProtocolClass.h中使用FirstProtocol協議,在ProtocolClass.m檔案中實現協議中得方法
ProtocolClass.h的程式碼如下:
1 2 3 4 5 |
#import #import "FirstProtocol.h" //在普通類中實現協議的方法如下 @interface ProtocolClass : NSObject @end |
ProtocolClass.m的程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#import "ProtocolClass.h" //不實現協議中必須的方法會產生警告 @implementation ProtocolClass //實現協議中必須的方法: required方法 -(void) requiredFunction { NSLog(@"RequiredFunction PS: 我是協議中required方法,不實現我會有警告!"); } //實現協議中可選的方法,不實現不會有警告 -(void) optionalFunction { NSLog(@"OptionalFunction PS: 我是protocol中得可選協議,不實現我,不會有警告!"); } @end |
測試的執行結果為:
1 2 |
2014-08-05 17:38:50.189 Memory[1907:303] RequiredFunction PS: 我是協議中required方法,不實現我會有警告! 2014-08-05 17:38:50.190 Memory[1907:303] OptionalFunction PS: 我是protocol中得可選協議,不實現我,不會有警告! |
在宣告物件的時候引入協議可以類比這Java中得泛型來學習, 例如宣告一個遵守FirstProtocol協議的物件: id obj;下面我們將用一個事例來介紹具體的用法
1.建立一個CalculatorProtocol的協議,在協議中宣告一個calculatorFunction的方法來進行兩個數的計算,檔名為:calculatorProtocol.h
程式碼如下:
1 2 3 4 5 |
#import //宣告計算方法 @protocol CalculatorProtocol -(void)calculatorFunction : (int) x withY : (int) y; @end |
2.在CalculatorClass類中新增新的方法,在這個類中有一個計算方法,需要對兩個數的計算,有一個引數是物件型別的必須遵循協議CalculatorProtocol,主要程式碼如下:
1 2 3 4 5 6 7 |
//實現傳入的物件必須服從協議的方法 -(void) calculatorFunction:(int)x withY:(int)y withObj:(id)obj { [obj calculatorFunction:x withY:y]; } |
3.定義遵循協議calculatorProtocol的類AddClass,在AddClass中實現calculatorFunction方法,實現兩個數相加的功能程式碼如下
1 2 3 4 5 6 7 8 9 10 11 |
#import "AddClass.h" @implementation AddClass //實現CalculatorProtocol必須的方法 -(void)calculatorFunction:(int)x withY:(int)y { int a = x + y; NSLog(@"AddClass PS: 我是實現協議的加方法%d + %d = %d", x, y, a); } @end |
4.新建一個DecClass類,同樣遵循calculatorProtocol協議,實現兩個數相減的功能,主要程式碼如下:
1 2 3 4 5 6 7 8 9 10 |
#import "DecClass.h" @implementation DecClass //實現protocol中必須實現的方法 -(void) calculatorFunction:(int)x withY:(int)y { int a = x - y; NSLog(@"DecClass PS: 我是重寫的減方法%d - %d = %d", x, y, a); } @end |
測試程式碼:
1 2 3 4 5 6 7 |
//測試協議物件 AddClass *add = [AddClass new]; //往protocol物件中的calculator方法中傳入符合協議的add物件 [pro calculatorFunction:2 withY:2 withObj:add]; DecClass *dec = [DecClass new]; [pro calculatorFunction:4 withY:3 withObj:dec]; |
執行結果如下:
1 2 |
2014-08-05 17:38:50.190 Memory[1907:303] AddClass PS: 我是實現協議的加方法2 + 2 = 4 2014-08-05 17:38:50.191 Memory[1907:303] DecClass PS: 我是重寫的減方法4 - 3 = 1 |
再舉一個理解協議更好理解協議的例子吧,我們宣告一個檔案協議,協議的內容是對檔案的讀和寫。我們在宣告一個檔案管理系統的類,只要是檔案能讀和寫就能放進我們的檔案管理系統進行管理。
1.指定可放入檔案管理系統檔案需要遵循的協議,協議中規定檔案必須有讀寫的功能
程式碼如下
1 2 3 4 5 |
#import @protocol FileManagerProtocol //讀方法 -(void) read; //寫方法 -(void) writer; @end |
2.編寫檔案管理系統,來對所有遵守協議的檔案來進行的統一的管理
程式碼如下:
宣告:
1 2 3 4 5 |
#import @protocol FileManagerProtocol //讀方法 -(void) read; //寫方法 -(void) writer; @end |
實現:
1 2 3 4 5 6 7 8 9 10 |
#import "FileManagerSystem.h" @implementation FileManagerSystem -(void)insertFileSystem:(id)file { [file read]; [file writer]; } @end |
3.定義新的檔案類來遵守我們的檔案讀寫協議,之後就可以放入到我們的管理系統中進行管理
檔案類1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#import #import "FileManagerProtocol.h" @interface File : NSObject @property (nonatomic,strong) NSString *fileName; @end #import "File.h" @implementation File //實現協議中的方法 -(void)read { NSLog(@"我是檔案%@,你可以對我進行閱讀",_fileName); } -(void)writer { NSLog(@"我是檔案%@,你可以對我進行修改",_fileName); } @end |
在定義一個簡歷檔案,同樣遵守我們的檔案協議
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#import #import "FileManagerProtocol.h" @interface JianLi : NSObject @property (nonatomic, strong) NSString *fileName; @end #import "JianLi.h" @implementation JianLi -(void)read { NSLog(@"對簡歷%@的讀", _fileName); } -(void)writer { NSLog(@"對簡歷%@的寫", _fileName); } @end |
然後我們可以把各種不同檔案但都遵循我們檔案協議的檔案放入到我們的檔案管理系統進行管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//宣告檔案,然後放入檔案管理系統 File *file = [File new]; file.fileName = @"浪潮之巔"; //例項化檔案二,只要符合檔案協議即可 File *file1 = [File new]; file1.fileName = @"file1"; JianLi *jianLi = [JianLi new]; jianLi.fileName = @"lusashi的簡歷"; //例項化檔案管理系統 FileManagerSystem *fileSystem = [FileManagerSystem new]; //把書加入到管理系統中 [fileSystem insertFileSystem:file]; [fileSystem insertFileSystem:file1]; [fileSystem insertFileSystem:jianLi]; |
執行結果:
1 2 3 4 5 6 |
2014-08-14 12:05:47.956 Memory[985:303] 我是檔案浪潮之巔,你可以對我進行閱讀 2014-08-14 12:05:47.958 Memory[985:303] 我是檔案浪潮之巔,你可以對我進行修改 2014-08-14 12:05:47.958 Memory[985:303] 我是檔案file1,你可以對我進行閱讀 2014-08-14 12:05:47.959 Memory[985:303] 我是檔案file1,你可以對我進行修改 2014-08-14 12:05:47.959 Memory[985:303] 對簡歷lusashi的簡歷的讀 2014-08-14 12:05:47.959 Memory[985:303] 對簡歷lusashi的簡歷的寫 |
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!