Objective-C马路成魔【12-分类和协议】
"ClassName.h"
@interface ClassName ( CategoryName )
// 方法声明
@end
上一篇多态性介绍中以前使用过Vector和Scalar的样例,
#import <Foundation/Foundation.h>
#import "Vector.h" @interface Vector (sub) -(Vector *) sub: (Vector *) v; @end
#import "Vector+sub.h" @implementation Vector (sub) -(Vector *) sub: (Vector *) v {
Vector *result = [[Vector alloc] init];
[result setVec1: vec1 - [v vec1] andVec2: vec2 - [v vec2]];
return result;
} @end
#import <Foundation/Foundation.h>
#import "Vector+sub.h" int main (int argc, const char * argv[]) { Vector *vecA =[[Vector alloc] init];
Vector *vecB =[[Vector alloc] init];
id result; //set the values
[vecA setVec1: 3.2 andVec2: 4.7];
[vecB setVec1: 32.2 andVec2: 47.7]; // print it
[vecA print];
NSLog(@" + ");
[vecB print];
NSLog(@" = ");
result = [vecA add: vecB];
[result print]; [vecA print];
NSLog(@" - ");
[vecB print];
NSLog(@" = ");
result = [vecA sub: vecB];
[result print]; // free memory
[vecA release];
[vecB release];
[result release];
return 0;
}
分类是在Java和C++等面向对象的语言中没有的概念,
从上面这个样例能够看到,分类提供了一种简单的方式。
用它能够将类的定义模块化到相关方法的组或分类中。
它还提供了扩展现有类定义的简便方式,而且不必訪问类的源码,也不须要创建子类。
#import "Fraction.h"
@interface Fraction (MathOps)
-(Fraction *) add: (Fraction *) f;
-(Fraction *) mul: (Fraction *) f;
-(Fraction *) sub: (Fraction *) f;
-(Fraction *) div: (Fraction *) f;
@end
注意,这既是接口部分的定义,也是现有接口部分的扩展。
因此。必须包含原接口部分,这样编译器就知道Fraction类。
依照惯例。作为分类的.h和.m文件的基本名称是由类的名称紧接着分类的名称。
比如:FractionMathOps.m;
一些程序猿使用符号“+”来分隔类和分类的名称,比方Fraction+MathOps.h。
只是不建议这样命名。
类的扩展:
创建一个未命名的分类。且在括号“()”之间不指定名字,这是一种特殊的情况。
这样的特殊的语法定义为类的扩展。
未命名类中声明的方法须要在主实现区域实现,而不是在分离的实现区域中实现。
未命名分类是很实用的,由于它们的方法都是私有的。
假设须要写一个类,并且数据和方法仅供这个类本身使用,未命名类比較合适。
关于分类的注意事项:
分类能够覆写该类中的还有一个方法,可是通常觉得这样的做法是做虐的设计习惯。所以须要注意:
第一、覆写了一个方法后。再也不能訪问原来的方法。(假设确实须要覆写方法。正确的选择可能是创建子类。)
第二、通过使用分类加入新的方法来扩展类不只影响这个类,同一时候也会影响它的全部子类。
第三、对象/分类命名对必须是唯一的。
由于大家使用的名称空间是程序代码、库、框架和插件共享的。
@protocol Graphics
-(void) onDraw;
@end
#import <Foundation/Foundation.h>
#import "Graphics.h" @interface Ellipse:NSObject <Graphics> { } @end
#import "Ellipse.h" @implementation Ellipse -(void)onDraw {
NSLog(@"绘制椭圆形");
} @end
#import <Foundation/Foundation.h>
#import "Graphics.h" @interface Triangle:NSObject <Graphics> { } @end
#import "Triangle.h" @implementation Triangle -(void)onDraw {
NSLog(@"绘制三角形");
} @end
与类的单个继承不同,
#import <Foundation/Foundation.h>
#import "Graphics.h"
#import "Ellipse.h"
#import "Triangle.h" int main (int argc, const char * argv[]) { id graphics;
graphics = [[Ellipse alloc] init];
[graphics onDraw];
[graphics release]; graphics = [[Triangle alloc] init];
[graphics onDraw];
[graphics release]; return 0;
}
从上面的样例能够看出:
协议是多个类共享的一个方法列表。
协议中列出的方法没有对应的实现,计划由其它人来实现。
协议提供了一种方式。用指定的名称定义一组多少有点相关的方法。
假设决定实现特定协议的全部方法,也就意味着要遵守(confirm to)或採用(adopt)这项协议。
定义一个协议非常easy:仅仅要使用@protocol指令。然后跟上你给出的协议名称。
比如:
@protocol NSCoping
- (id) copyWithZone: (NSZone *) zone;
@end
这里再提到两个重要的协议:
NSCoding
假设你的类採用NSCopying协议,则必须实现copyWithZone:的方法。
通过在@interface行的一对尖括号(<....>)内列出协议名称。能够告知编译器你正在採用的一个协议。
这项协议的名称放在类名和它的父类名称之后,
比如:
@interface AddressBook:NSObject <NSCoping>
假设你的类採用多项协议,仅仅需把它们都列在尖括号里,并用逗号分开。比如:
@interface AddressBook:NSObject <NSCoping, NSCoding>
假设你定义了自己的协议,那么不必由自己实现它。
假设一个类遵守NSCoping协议。则它的子类也遵守NSCoping协议
(只是并不意味着对该子类而言。这些方法得到了正确的实现)。
- (void) requiredMethod;
@optional
- (void) anOptionalMethod;
- (void) anotherOptionalMethod;
@required
- (void) anotherRequiredMethod;
@end
注意。这里使用了@optional指令。
该指令之后列出的全部方法都是可选的。
@required指令之后的是须要的方法。
注意,协议不引用不论什么类,它是无类的(classless)。
不论什么类都能够遵循MyProtocol协议。
能够使用conformsToProtocol:方法检查一个对象是否遵循某些协议。
比如:
if ([currentObject conformsToProtocol: @protocol (MyProtocol)] == YES) {
...
}
这里使用的专用@protocol指令用于获取一个协议名称,并产生一个Protocol对象。
conformsToProtocol:方法期望这个对象作为它的參数。
通过在类型名称之后的尖括号里加入协议名称。能够借助编译器来检查变量的一致性。
比如:
id <Drawing> currentObject;
这告知编译器currentObject将包括遵守Drawing协议的对象。
假设这个变量保存的对象遵守多项协议,则能够列出多项协议 ,
例如以下面代码:
id <NSCoping, NSCoding> myDocument;
定义一项协议时。能够扩展现有协议的定义。
如:
@protocol Drawing3D <Drawing> Drawing3D 协议也採用了Drawing协议。
最后要说的是。分类也是能够採用一项协议。
和类名一样,协议名必须是唯一的。
代理:
协议也是一种两个类之间的接口定义。
定义了协议的类能够看做是将协议定义的方法代理给了实现它们的类。
非正式(informal)协议:是一个分类,列出了一组方法但并没有实现它们。
因此,非正式分类一般是为根类定义的。有时,非正式协议也称为抽象(abstract)协议。
非正式协议实际上仅仅是一个名称下的一组方法。
声明非正式协议的类自己并不实现这些方法。
而且选择实现这些方法中的子类须要在它的接口部分又一次声明这些方法。
同一时候还要实现这些方法中的一个或多个。
注意:前面描写叙述的@optional指令加入到了Objective-C 2.0语言中,用于代替非正式协议的使用。
合成对象:
能够定义一个类包括其它类的一个或多个对象。
这个新类的对象就是所谓的合成(composite)对象,由于它是由其它对象组成的。
子类依赖于父类。改变了父类有可能会使得子类中的方方法不起作用。
版权声明:本文博客原创文章,博客,未经同意,不得转载。
Objective-C马路成魔【12-分类和协议】的更多相关文章
- Objective-C马路成魔【14-关键C语言功能】
郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠,支持郝萌主.捐赠数额任意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 这里介绍一 ...
- 成魔笔记1——先入IT,再成魔
关于我为什么要写这个博客的原因,做一个简单的解释.因为报考的一时兴起,我选择了软件专业.可是三年下来,感觉自己没做多少事,也没收获到多少东西.很多时候都是老师讲什么,都是完全陌生的东西,跟不上教学的思 ...
- Objective-C之成魔之路【0-序章】
郝萌主倾心贡献,尊重作者的劳动成果.请勿转载. 假设文章对您有所帮助.欢迎给作者捐赠,支持郝萌主,捐赠数额任意.重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 C语言首创 ...
- 第12讲 | TCP协议(下):西行必定多妖孽,恒心智慧消磨难
第12讲 | TCP协议(下):西行必定多妖孽,恒心智慧消磨难 如何做个靠谱的人? 有问有答,任务发送和接收有记录,完成有反馈. 如何实现一个靠谱的协议? TCP 协议使用的也是同样的模式.为了保证顺 ...
- 机器学习入门12 - 分类 (Classification)
原文链接:https://developers.google.com/machine-learning/crash-course/classification/ 1- 指定阈值 为了将逻辑回归值映射到 ...
- Objective-C之成魔之路【5-选择结构】
郝萌主倾心贡献.尊重作者的劳动成果,请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠,支持郝萌主.捐赠数额任意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 Objec ...
- Objective-C之成魔之路【16-使用文件】
郝萌主倾心贡献,尊重作者的劳动成果.请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠.支持郝萌主,捐赠数额任意.重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 语言的设计 ...
- Objective-C之成魔之路【9-类构造方法和成员变量作用域、以及变量】
郝萌主倾心贡献,尊重作者的劳动成果.请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额任意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 构造方法 ...
- 将decimal类型的数据转成2.12这样价钱的显示方式
UnitPrice = string.Format("{0:.00}", m.UnitPrice),
随机推荐
- 对于COM对象使用ComPtr代替传统指针
对于COM对象来说使用传统指针比较麻烦,还要记得Release()防止内存泄漏,一不小心就会出现各种各样的问题.针对这种问题微软提供了对于COM对象的智能指针ComPtr,这里是官方文档https:/ ...
- CAS实现SSO单点登录原理(转)
1. CAS 简介 1.1. What is CAS ? CAS ( Central Authentication Service ) 是 Yale 大学发起的一个企业级的.开源的项目,旨 ...
- 完全背包(南阳oj311)(完全背包)
全然背包 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描写叙述 直接说题意,全然背包定义有N种物品和一个容量为V的背包.每种物品都有无限件可用. 第i种物品的体积是c.价值 ...
- 开源 自由 java CMS - FreeCMS1.9 评论管理
项目地址:http://code.google.com/p/freecms/ 评论管理 1. 评论管理 从左側管理菜单点击评论管理进入. 2. 评论审核 选择须要审核的评论,然后点击"审核& ...
- LeetCodeOJ. Longest Common Prefix
试题请參见: https://oj.leetcode.com/problems/longest-common-prefix/ 题目概述 Write a function to find the lon ...
- 开源Math.NET基础数学类库使用(12)C#随机数扩展方法
原文:[原创]开源Math.NET基础数学类库使用(12)C#随机数扩展方法 本博客所有文章分类的总目录:http://www.cnblogs.com/asxinyu/p ...
- Bug记录:微博的Java SDK返回经纬度错误
现象:美国的坐标点可能会定位到西藏地区-后发现原来负经度经解析后,均变成正的! 源码: private void getGeoInfo(String geo) { StringBuffer value ...
- JQuery EasyUI学习框架
前言 前端技术,新项目的开发拟使用EasyUI框架(基于EasyUI丰富UI组件库),项目负责人的提示EasyUI分配给我这个任务.发展前,我需要这对于一个新手EasyUI框架学习一些基本的入门.记录 ...
- oracle_控制用户权限
oracle_控制用户权限 ①对 限制 数据库安全: 系统安全 数据安全性 系统权限: 对于数据库的权限 对象权限: 操作数据库对象的权限 1.系统权限 ...
- Task的异步模式
Task的异步模式 返回该系列目录<基于Task的异步模式--全面介绍> 生成方法 编译器生成 在.NET Framework 4.5中,C#编译器实现了TAP.任何标有async关键字的 ...