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

        代碼如下:

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
#import "ExtensionTest.h"
 
@interface ExtensionTest ()
-( void )privateFunction1;
 
@end

        

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

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

            Extension.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
#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 <Foundation/Foundation.h>
//創建第一個protocol
@protocol FirstProtocol <NSObject>
//為protocol里加入必須實現的方法
@required
-( void )requiredFunction;
 
//定義可選的方法
@optional
-( void )optionalFunction;
 
@end

 

    ​    ​    ​2.新建一個類命名為ProtocolClass, 在ProtocolClass.h中使用FirstProtocol協議,在ProtocolClass.m文件中實現協議中得方法

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

1
2
3
4
5
#import <Foundation/Foundation.h>
#import "FirstProtocol.h"
//在普通類中實現協議的方法如下<>
@interface ProtocolClass : NSObject<FirstProtocol>
@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<FirstProtocol> obj;下面我們將用一個事例來介紹具體的用法

    ​    ​    ​1.創建一個CalculatorProtocol的協議,在協議中聲明一個calculatorFunction的方法來進行兩個數的計算,文件名為:calculatorProtocol.h

     ​    ​    ​    ​代碼如下: ​    ​

1
2
3
4
5
#import <Foundation/Foundation.h>
//聲明計算方法
@protocol CalculatorProtocol <NSObject>
-( 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<CalculatorProtocol>)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.指定可放入文件管理系統文件需要遵循的協議,協議中規定文件必須有讀寫的功能

  代碼如下

#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的簡歷的寫

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM