本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,但愿带给你们更好,更真实的转换历程体验。本文继续上一篇随笔《从C#到Object C,按部就班学习苹果开发(2)--Objective-C和C#的差别》,继续对比介绍它们二者之间的差别,以便咱们从C#阵营过来的人员加深印象,深刻了解Objective-C语言的特性。本篇随笔主要针对Objective-C里面的分类(category)和协议Protocal概念的理解进行介绍。html
若是咱们使用过C#,咱们都知道,C#里面有一个叫作扩展函数的东西,能够在不继承已有类的状况下,给存在的类增长一些本来没有的接口函数,Objective-C的分类概念和这个很类似,甚至能够说是同一类型的东西,虽然不知道他们谁先谁后出现,这个东西的引入,能使得编程方面更加丰富高效。编程
Objective-C提供了一种不同凡响的方式——Category,能够动态的为已经存在的类添加新的行为。这样能够保证类的原始设计规模较小,功能增长时再逐步扩展。使用Category对类进行扩展时,不须要访问其源代码,也不须要建立子类。Category使用简单的方式,实现了类的相关方法的模块化,把不一样的类方法分配到不一样的分类文件中。不过Category并不能给类扩展出属性,这点要注意,由于Object C不支持这样的属性扩展。框架
分类(Category)的定义语法以下所示。模块化
@interface ClassName (CategoryName) @end
这里好像它们还有一个约定俗成的习惯,将声明文件和实现文件名称统一采用“原类名+Category”的方式命名。因此OC的这种功能虽然和C#功能差很少,可是这点约定和C#不同,C#无论你放到哪里都行,可是咱们仍是会应该尊重它的规则。函数
例如,咱们给XYZPerson类增长一个扩展方法的定义以下所示,这个定义的函数约定是放到文件"XYZPerson+XYZPersonNameDisplayAdditions.h"里面。学习
#import "XYZPerson.h" @interface XYZPerson (XYZPersonNameDisplayAdditions) - (NSString *)testMethod; @end
那么它的实现代码以下所示,它的代码约定是放到 "XYZPerson+XYZPersonNameDisplayAdditions.m"里面。ui
#import "XYZPerson+XYZPersonNameDisplayAdditions.h" @implementation XYZPerson (XYZPersonNameDisplayAdditions) - (NSString *)testMethod { return [NSString stringWithFormat:@"%@, %@", self.lastName, self.firstName]; } @end
在C#里面,扩展方法是命名空间相关的,一旦跳出了命名空间的范围,这个扩展函数就不在起做用,而Objective-C的这个和类同样,没有命名空间的概念,所以在扩展的时候,须要当心谨慎一点,不然容易致使分类的接口和类自己发生冲突。基于这个缘由,因此苹果建议也是给分类的接口增长一个前缀,命名则采用接口的一向规则,以下面代码所示。this
@interface NSSortDescriptor (XYZAdditions) + (id)xyz_sortDescriptorWithKey:(NSString *)key ascending:(BOOL)ascending; @end
这样扩展方法名称虽然长了一点,可是基本上确保和普通的接口方法不会发生冲突了。spa
Category的使用场景:设计
还有一种成为类扩展的功能,它是针对存在代码的类的状况,也就是你的类代码和你扩展的源码是同时编译的状况下。
类扩展的方法和上面的分类相似,他们不须要写扩展分类的名称,这个有点像匿名扩展分类的概念了,以下所示
@interface ClassName () @end
这个匿名的扩展分类,和普通的Category不一样,它除了能够方法外,还能够添加属性或者变量的。
这个概念有很大程度上和C#的接口相似,可是它有所不一样,它能够可选的实现接口@optional,也有必选的实现接口@required,虽然Objective-C里面已经有一个关键字 @interface,不过这个和Protocal仍是有不一样的。
和C#的接口同样,这种协议也能够继承自另一个Protocal,也就是他们能够有继承关系。
@protocol NewProtocal <Protocal> @end
因为Objective-C开发的不少应用,如IOS的应用,他们在MVC的开发模型里面,都大量使用了代理模式,这种Protocal很好的处理了这种关系。在iOS和OS X开发中,Apple采用了大量的代理模式来实现MVC中View和Controller的解耦。
例如UIView产生的全部事件,都是经过委托的方式交给Controller完成。根据约定,框架中后缀为Delegate的都是Protocol,例如UIApplicationDelegate,UIWebViewDelegate等。
在C#里面有不少如IClonable, IEnumerable这样的接口,只要实现了,就能实现克隆和枚举,在Objective-C里面,这个就是可使用Protocal来替代了,若是某个协议继承了NSObject,那么这是表明在此声明的协议,是NSObject协议的衍生协议(不是NSObject类),也就是说,这里的语境理解NSObject是一个协议,若是是在@Interface里面的继承关系,那么那个就是NSObject对象。有点意思哦。
下面是一个可选和必选的协议定义例子。
@protocol XYZPieChartViewDataSource - (NSUInteger)numberOfSegments; - (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex; @optional - (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex; - (BOOL)shouldExplodeSegmentAtIndex:(NSUInteger)segmentIndex; @required - (UIColor *)colorForSegmentAtIndex:(NSUInteger)segmentIndex; @end
因为协议有可选和必选,若是咱们想知道某个动态的对象是否具备某个接口函数,就是经过@selector操做符来进行判断的。
NSString *thisSegmentTitle; if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) { thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index]; }
和C#的接口定义相似,Objective-C的一个类对象它能够实现多的协议,以下例子是一个类的接口定义实现几个协议的状况。
@interface MyClass : NSObject <MyProtocol, AnotherProtocol, YetAnotherProtocol> ... @end
这样就实现了MyClass对象只有一个基类对象,可是能够实现多个协议(C#是多个接口)的状况。