天天看點

Objective-C中的類目,延展,協定

  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

22

//CategoryTest.h

#import <Foundation/Foundation.h>

@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的類目,來進行對類方法的擴充,

        代碼如下:

//  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

        實作檔案:

//

//  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

    測試運作結果:

2014-08-04 17:08:46.187 Memory[1621:303] 魯大師,你好!我是通過類目擴充的方法!

    2.對把類中不同的功能子產品分成不同的檔案

        1.給上面的類建立兩個類目,類目中分别存放執行個體變量的getter和setter方法,為了節省篇幅下面給出其中一個類目的事例;

            接口的聲明:

//  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

        類目的實作檔案:

//  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

        對代碼測試的結果:

2014-08-04 17:08:46.188 Memory[1621:303] ludashi1 = 10, ludashi2 = 20

    3.非正式協定

            非正式協定就是給NSObject類建立的類目又叫做非正式協定, 非正式協定一般不需要進行實作,一般在子類中進行方法的重寫。代碼在這就不贅述啦!

類目的優缺點分析(下面有些是個人觀點,不對之處請批評指正)

        優點:上面的功能也是類目存在的重要原因之所在,在這就不重複了

        局限性: 在類目中隻可以為類添加方法,不能添加執行個體變量; 類目中得方法的優先級要高。

二.Objective-C中的延展(Extension)

        簡單的說匿名類目就是延展,在延展中定義的方法是類私有的方法隻能在類的内部調用,定義延展的方式就是把類目中括号中得名字省略掉,括号保留這就是延展。其實在延展中定義的方法不是真正的私有方法和C++, Java中得方法還有所差別,在類初始化的檔案中引入相應延展的頭檔案,其延展對應的方法也是可以通路的。是通過隐藏延展的頭檔案來達到方法私有 的。

        定義私有方法有以下三種方式:

        1.通過延展來實作方法的私有,延展的頭檔案獨立。這種方法不能實作真正的方法私有,當在别的檔案中引入延展的頭檔案,那麼在這個檔案中定義的類的對象就可以直接調用在延展中定義所謂私有的方法。demo如下:

           代碼如下:

            延展相應的頭檔案,延展方法的實作在類對應的.m中給出實作方法:

#import "ExtensionTest.h"

@interface ExtensionTest ()

-(

void

)privateFunction1;

@end

        2.第二種實作延展的方式是延展沒有獨立的頭檔案,在類的實作檔案.m中聲明和實作延展,這種方法可以很好的實作方法的私有,因為在OC中是不能引入.m的檔案的

        3.第三種實作方法私有的方式是在.m檔案中得@implementation中直接實作在@interface中沒有聲明的方法,這樣也可以很好的實作方法的私有。

            Extension.m中的代碼

23

24

25

26

27

28

29

30

31

32

33

34

35

36

#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"也可以調用其裡面聲明的相應的方法

    ​    ​測試代碼如下:

//測試延展

ExtensionTest *extension = [ExtensionTest 

new

];

[extension publicFunction];

[extension privateFunction1];

    ​    ​運作結果:

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的

#import <Foundation/Foundation.h>

//建立第一個protocol

@protocol FirstProtocol <NSObject>

//為protocol裡加入必須實作的方法

@required

-(

void

)requiredFunction;

//定義可選的方法

@optional

-(

void

)optionalFunction;

@end

    ​    ​    ​2.建立一個類命名為ProtocolClass, 在ProtocolClass.h中使用FirstProtocol協定,在ProtocolClass.m檔案中實作協定中得方法

    ​    ​    ​    ​ProtocolClass.h的代碼如下:

#import <Foundation/Foundation.h>

#import "FirstProtocol.h"

//在普通類中實作協定的方法如下<>

@interface ProtocolClass : NSObject<FirstProtocol>

@end

    ​    ​    ​ProtocolClass.m的代碼如下:

#import "ProtocolClass.h"

//不實作協定中必須的方法會産生警告

@implementation ProtocolClass

//實作協定中必須的方法: required方法

-(

void

) requiredFunction

{

NSLog(@

"RequiredFunction PS: 我是協定中required方法,不實作我會有警告!"

);

}

//實作協定中可選的方法,不實作不會有警告

-(

void

) optionalFunction

{

NSLog(@

"OptionalFunction PS: 我是protocol中得可選協定,不實作我,不會有警告!"

);

}

@end

    ​    ​    測試的運作結果為:

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<FirstProtocol> obj;下面我們将用一個事例來介紹具體的用法

    ​    ​    ​1.建立一個CalculatorProtocol的協定,在協定中聲明一個calculatorFunction的方法來進行兩個數的計算,檔案名為:calculatorProtocol.h

     ​    ​    ​    ​代碼如下: ​    ​

#import <Foundation/Foundation.h>

//聲明計算方法

@protocol CalculatorProtocol <NSObject>

-(

void

)calculatorFunction : (

int

) x  withY : (

int

) y;

@end

    ​    ​

    ​      2.在CalculatorClass類中添加新的方法,在這個類中有一個計算方法,需要對兩個數的計算,有一個參數是對象類型的必須遵循協定CalculatorProtocol,主要代碼如下:

//實作傳入的對象必須服從協定的方法

-(

void

) calculatorFunction:(

int

)x

withY:(

int

)y

withObj:(id<CalculatorProtocol>)obj

{

[obj calculatorFunction:x withY:y];

}

    ​    ​   3.定義遵循協定calculatorProtocol的類AddClass,在AddClass中實作calculatorFunction方法,實作兩個數相加的功能代碼如下

#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協定,實作兩個數相減的功能,主要代碼如下:

#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

    ​測試代碼:

//測試協定對象

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];

    ​運作結果如下:

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.指定可放入檔案管理系統檔案需要遵循的協定,協定中規定檔案必須有讀寫的功能

  代碼如下

#import <Foundation/Foundation.h>

@protocol FileManagerProtocol <NSObject>
//讀方法
-(void) read;
//寫方法
-(void) writer;
@end      

  

  2.編寫檔案管理系統,來對所有遵守協定的檔案來進行的統一的管理

  代碼如下:

  聲明:

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

@interface FileManagerSystem : NSObject
-(void) insertFileSystem: (id<FileManagerProtocol>) file;
@end      

  實作:

#import "FileManagerSystem.h"

@implementation FileManagerSystem
-(void)insertFileSystem:(id<FileManagerProtocol>)file
{
    [file read];
    [file writer];
}

@end      

  3.定義新的檔案類來遵守我們的檔案讀寫協定,之後就可以放入到我們的管理系統中進行管理

  檔案類1

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

@interface File : NSObject<FileManagerProtocol>
@property (nonatomic,strong) NSString *fileName;
@end


#import "File.h"
@implementation File
//實作協定中的方法
-(void)read
{
    NSLog(@"我是檔案%@,你可以對我進行閱讀",_fileName);
}

-(void)writer
{
    NSLog(@"我是檔案%@,你可以對我進行修改",_fileName);
}

@end      

  在定義一個履歷檔案,同樣遵守我們的檔案協定

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

@interface JianLi : NSObject<FileManagerProtocol>
@property (nonatomic, strong) NSString *fileName;
@end

#import "JianLi.h"

@implementation JianLi
-(void)read
{
    NSLog(@"對履歷%@的讀", _fileName);
}
-(void)writer
{
    NSLog(@"對履歷%@的寫", _fileName);
}

@end      

  然後我們可以把各種不同檔案但都遵循我們檔案協定的檔案放入到我們的檔案管理系統進行管理

1     //聲明檔案,然後放入檔案管理系統
 2     File *file = [File new];
 3     file.fileName = @"浪潮之巅";
 4     
 5     //執行個體化檔案二,隻要符合檔案協定即可
 6     File *file1 = [File new];
 7     file1.fileName = @"file1";
 8     
 9     JianLi *jianLi = [JianLi new];
10     jianLi.fileName = @"lusashi的履歷";
11 
12     //執行個體化檔案管理系統
13     FileManagerSystem *fileSystem = [FileManagerSystem new];
14     
15     
16     
17     //把書加入到管理系統中
18     [fileSystem insertFileSystem:file];
19     [fileSystem insertFileSystem:file1];
20     [fileSystem insertFileSystem:jianLi];      

  運作結果:

1 2014-08-14 12:05:47.956 Memory[985:303] 我是檔案浪潮之巅,你可以對我進行閱讀
2 2014-08-14 12:05:47.958 Memory[985:303] 我是檔案浪潮之巅,你可以對我進行修改
3 2014-08-14 12:05:47.958 Memory[985:303] 我是檔案file1,你可以對我進行閱讀
4 2014-08-14 12:05:47.959 Memory[985:303] 我是檔案file1,你可以對我進行修改
5 2014-08-14 12:05:47.959 Memory[985:303] 對履歷lusashi的履歷的讀
6 2014-08-14 12:05:47.959 Memory[985:303] 對履歷lusashi的履歷的寫      

作者:青玉伏案

出處:http://www.cnblogs.com/ludashi/

本文版權歸作者和共部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

如果文中有什麼錯誤,歡迎指出。以免更多的人被誤導。

收履歷:某網際網路公司,招聘iOS/Android靠譜工程師,入職後,可内部聯系樓主,有小禮品贈送,有意者可郵箱投遞履歷:[email protected]