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.能夠用類目把類的實現按功能模塊分爲不一樣的文件ui
3.能夠用來擴展NSObject類的方法,也叫作非正式協議atom
編譯環境說明: iMac OS X 10.9 (13A603) 編譯器:XCode 5.0.2版本spa
1.給已有的類擴充方法code
在Xcode中新建CategoryTest類,在新建類中聲明兩個實例變量,在實現類中重寫description方法,打印輸出兩個實例變量的值orm
代碼以下
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中被實現
|
3、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的簡歷的寫