obj-c編程08:分類和協議
在第8篇文章裏我們來聊聊如何擴展一個類的方法和實例變量,我們首先來看一下命名分類如何擴展一個類。在下麵的代碼中,首先定義一個類Player用來定義普通球員,如果第三方開發者發現普通球員缺少了一些方法,則可以用分類ext來擴充嘍:
代碼1:默認的Player類
Player.h文件:
#import<Foundation/Foundation.h> @interfacePlayer:NSObject{ intnumber; intage; } -(void)show; -(id)init:(int)n:(int)age; @end
Player.m文件:
#import"Player.h" @implementationPlayer -(id)init:(int)n:(int)age_v{ self= [super init]; if(self){ number= n; age= age_v; } returnself; } -(void)show{ NSLog(@"playerx ,number:%d,age:%d",number,age); } @end
test.m文件:
#import"Player.h" intmain(int argc,char **argv) { @autoreleasepool{ Player*p = [[Player alloc] init: 1 :20]; [pshow]; } return0; }
編譯執行結果如下:
apple@kissAir:Player$clang -fobjc-arc -framework Foundation Player.m test.m -o main
apple@kissAir:Player$./main
2014-06-3017:55:56.053 main[3862:507] player x ,number:1,age:20
現在一個第三方軟件公司覺得球員球員太不活潑,so他們決定給球員添加方法say和train:
Player_ext.h文件
#import"Player.h" @interfacePlayer (ext) //@propertyint power; //-(id)init:(int)n:(int)age :(int)power; -(void)say; -(void)train; @end
Player_ext.m文件
#import"Player_ext.h" @implementationPlayer (ext) //@synthesizepower; /* -(id)init:(int)n :(int)age_v :(int)pow{ self= [super init :n :age_v]; if(self){ power= pow; } returnself; } */ -(void)say{ NSLog(@"player[n:%d]want to say : hello!",number); } -(void)train{ NSLog(@"player[n:%d]is training...",number); } @end
test.m文件
//#import"Player.h" #import"Player_ext.h" intmain(int argc,char **argv) { @autoreleasepool{ Player*p = [[Player alloc] init: 1 :20]; [pshow]; [psay]; [ptrain]; } return0; }
我們編譯運行看看結果咯:
apple@kissAir:Player$clang -fobjc-arc -framework Foundation Player.m Player_ext.mtest.m -o main
apple@kissAir:Player$./main
2014-06-3018:16:09.050 main[4246:507] player x ,number:1,age:20
2014-06-3018:16:09.052 main[4246:507] player[n:1] want to say : hello!
2014-06-3018:16:09.053 main[4246:507] player[n:1] is training...
我們發現在命名分類中試圖添加實例變量是不允許的,隻能在未命名分類中添加,而且未命名分類中聲明方法的實現隻能放在主類的實現中。下麵修改代碼,增加power屬性,並且train動作是要耗費power的,遂修改該方法,同時新增init方法如下:
@implementation Player (ext) //@synthesize power; /* -(id)init :(int)n :(int)age_v :(int)pow{ self = [super init :n :age_v]; if(self){ power = pow; } return self; } */ -(void)say{ NSLog(@"player[n:%d] want to say : hello!",number); } -(void)train{ NSLog(@"player[n:%d:pow:%d] is training...power is down to %d",\ number,self.power,self.power -= 10); }
Player.h文件
#import <Foundation/Foundation.h> @interface Player:NSObject{ int number; int age; } -(void)show; -(id)init:(int)n :(int)age; @end @interface Player () @property int power; -(id)init :(int)n :(int)age :(int)power; @end
Player.m文件
#import "Player.h" @implementation Player @synthesize power; -(id)init:(int)n :(int)age_v{ self = [super init]; if(self){ number = n; age = age_v; } return self; } -(id)init :(int)n :(int)age_v :(int)pow{ self = [super init]; if(self){ self = [self init :n :age_v]; power = pow; } return self; } -(void)show{ NSLog(@"player x ,number:%d,age:%d,power:%d",number,age,power); } @end
test.m文件
#import "Player_ext.h" int main(int argc,char **argv) { @autoreleasepool{ Player *p = [[Player alloc] init: 1 :20 :100]; [p show]; [p say]; [p train]; [p show]; } return 0; }
編譯運行結果如下:
apple@kissAir: Player$clang -fobjc-arc -framework Foundation Player.m Player_ext.m test.m -o main
apple@kissAir: Player$./main
2014-06-30 18:52:29.237 main[4822:507] player x ,number:1,age:20,power:100
2014-06-30 18:52:29.239 main[4822:507] player[n:1] want to say : hello!
2014-06-30 18:52:29.240 main[4822:507] player[n:1:pow:100] is training...power is down to 90
2014-06-30 18:52:29.240 main[4822:507] player x ,number:1,age:20,power:90
有球員就有教練啊,現在添加教練類。教練類和球員類有共性的地方哦,就是都有say和train方法。這個共性的地方不妨就用協議來描述吧,需要說明的是教練還有一個召開發布會方法,該方法球員是沒有的,我們把它作為一個可選方法放入協議。為了方便就把教練類放在test.m中嘍:
Player.h文件
#import <Foundation/Foundation.h> @protocol Actions -(void)say; //必須存在 @optional -(void)convoke; //可選方法 @required -(void)train; //必須存在 @end @interface Player:NSObject{ int number; int age; } -(void)show; -(id)init:(int)n :(int)age; @end @interface Player () @property int power; -(id)init :(int)n :(int)age :(int)power; @end
Player_ext.h文件
#import "Player.h" @interface Player (ext) <Actions> //@property int power; //-(id)init:(int)n :(int)age :(int)power; -(void)say; -(void)train; @end
test.m文件
//#import "Player.h" #import "Player_ext.h" @interface Coach:NSObject <Actions> @end @implementation Coach -(void)say{ NSLog(@"coach say : hello!"); } -(void)train{ NSLog(@"coach is leading train..."); } -(void)convoke{ NSLog(@"coach is convoking a meeting..."); } @end int main(int argc,char **argv) { @autoreleasepool{ Player *p = [[Player alloc] init: 1 :20 :100]; Coach *c = [[Coach alloc] init]; [p show]; [c say]; [c convoke]; [c train]; [p say]; [p train]; [p show]; } return 0; }
編譯運行結果如下:
apple@kissAir: Player$./main
2014-06-30 20:33:24.930 main[6466:507] player x ,number:1,age:20,power:100
2014-06-30 20:33:24.932 main[6466:507] coach say : hello!
2014-06-30 20:33:24.933 main[6466:507] coach is convoking a meeting...
2014-06-30 20:33:24.933 main[6466:507] coach is leading train...
2014-06-30 20:33:24.934 main[6466:507] player[n:1] want to say : hello!
2014-06-30 20:33:24.934 main[6466:507] player[n:1:pow:100] is training...power is down to 90
2014-06-30 20:33:24.934 main[6466:507] player x ,number:1,age:20,power:90
如果要添加多個協議語法為: @interface A <p_a,p_b>
最後我們可以用反射方法測試類是否遵守協議:
Protocol *actions = @protocol(Actions); Player *p = [[Player alloc] init: 1 :20 :100]; Coach *c = [[Coach alloc] init]; if([p conformsToProtocol: actions]){ NSLog(@"Player abide protocol Actions"); //Coach同樣遵守 } //對於可選方法我們可以用一般的respondsToSelector方法來測試: if([c respondsToSelector :@selector(convoke)]){ NSLog(@"Coach has convoke method"); }
最後更新:2017-04-03 05:46:49