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");
		}


相关文章
|
前端开发 测试技术
你发现一个bug,如何定位这个是前端还是后端缺陷?建议收藏
你发现一个bug,如何定位这个是前端还是后端缺陷?建议收藏
1018 0
|
存储 监控 安全
大厂案例 - 腾讯万亿级 Elasticsearch 架构实践1
大厂案例 - 腾讯万亿级 Elasticsearch 架构实践
502 0
|
存储 关系型数据库 MySQL
服务器数据恢复—EVA存储异常断电重启后虚拟机无法启动的数据恢复方案
服务器存储数据恢复环境: 某品牌EVA8400,服务器上安装VMware ESXi虚拟化平台,虚拟机的虚拟磁盘包括数据盘(精简模式)+快照数据盘,部分虚拟机中运行oracle数据库和mysql数据库。 服务器存储故障&检测: 存储异常断电重启后,存储中一台虚拟机无法启动。工作人员推测故障原因是异常断电导致电源模块出现故障,清空cache后重新启动存储发现该虚拟机仍无法正常启动。
|
机器学习/深度学习 人工智能 自然语言处理
技术小白能看懂的ChatGPT原理介绍
网上有关 ChatGPT 的原理介绍文章一大堆,要么是从 NLP 的历史开始讲起,要么是上数 GPT 3 代,内容都相对冗长和复杂。其实 ChatGPT 的原理并不难理解,我将以最通俗易懂的方式为技术小白解读,帮助大家更好地了解这一技术
971 1
技术小白能看懂的ChatGPT原理介绍
sdkman 安装以及 graalvm安装
sdkman 安装以及 graalvm安装
212 0
|
存储 搜索推荐 数据挖掘
PDS(Personal/Enterprise Data Storage)
PDS 是一款集数据存储、管理和智能分析于一体的云存储平台,适用于个人和企业用户。它提供了目录、文件管理功能,以及影像内容的分类打标、人脸聚类等智能分析功能,基于内容的智能搜索能力,用户体系以及第三方身份系统接入能力。用户可基于此开发一套面向企业或个人的网盘系统。PDS 还提供了一些官方应用,可与您的系统组合使用,简化您的开发。
795 2
|
存储 SQL Cloud Native
基于Ganos的栅格引擎开展区域面雨量分析
本文介绍了由阿里云联合阿里巴巴达摩院数据库与存储实验室研发的多模态时空数据库Ganos之栅格引擎(Ganos Raster)在水利/气象领域的分析场景应用。Ganos通过在数据库中原生内置影像与格网数据的存储、检索与分析能力,为气象、水利、资源管理、应急、传媒等客户提供海量栅格数据的分析挖掘能力。通过阅读本文,用户可以更好的理解Ganos栅格模型的存储结构与相关分析能力,助力业务开发走向便捷。
|
Android开发 iOS开发
AppsFlyer 研究(九)OneLink模板配置步骤
AppsFlyer 研究(九)OneLink模板配置步骤
625 0
|
安全 测试技术
漏洞复现--CVE-2020-0796getshell
漏洞复现--CVE-2020-0796getshell
漏洞复现--CVE-2020-0796getshell