閱讀69 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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他們決定給球員添加方法saytrain:


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

  上一篇:go Swift擴展(Extension)
  下一篇:go ≪統計學習精要(The Elements of Statistical Learning)≫課堂筆記(三)