本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验。本文继续上一篇随笔《从C#到Object C,循序渐进学习苹果开发(2)--Objective-C和C#的差异》,继续对比介绍它们两者之间的差异,以便我们从C#阵营过来的人员加深印象,深入了解Objective-C语言的特性。本篇随笔主要针对Objective-C里面的分类(category)和协议Protocal概念的理解进行介绍。

1、分类(category)概念和使用

如果我们使用过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"里面。

#import "XYZPerson+XYZPersonNameDisplayAdditions.h"

@implementation XYZPerson (XYZPersonNameDisplayAdditions)
- (NSString *)testMethod {
return [NSString stringWithFormat:@"%@, %@", self.lastName, self.firstName];
}
@end

在C#里面,扩展方法是命名空间相关的,一旦跳出了命名空间的范围,这个扩展函数就不在起作用,而Objective-C的这个和类一样,没有命名空间的概念,因此在扩展的时候,需要小心谨慎一点,否则容易导致分类的接口和类本身发生冲突。基于这个原因,所以苹果建议也是给分类的接口增加一个前缀,命名则采用接口的一贯规则,如下面代码所示。

@interface NSSortDescriptor (XYZAdditions)
+ (id)xyz_sortDescriptorWithKey:(NSString *)key ascending:(BOOL)ascending;
@end

这样扩展方法名称虽然长了一点,但是基本上确保和普通的接口方法不会发生冲突了。

Category的使用场景:

1、当你在定义类的时候,在某些情况下(例如需求变更),你可能想要为其中的某个或几个类中添加方法。
2、一个类中包含了许多不同的方法需要实现,而这些方法需要不同团队的成员实现
3、当你在使用基础类库中的类时,你可能希望这些类实现一些你需要的方法。
 
遇到以上这些需求,Category可以帮助你解决问题。当然,使用Category也有些问题需要注意,
1、Category可以访问原始类的实例变量,但不能添加变量,如果想添加变量,可以考虑通过继承创建子类。
2、Category可以重载原始类的方法,但不推荐这么做,这么做的后果是你再也不能访问原来的方法。如果确实要重载,正确的选择是创建子类。
3、和普通接口有所区别的是,在分类的实现文件中可以不必实现所有声明的方法,只要你不去调用它。

还有一种成为类扩展的功能,它是针对存在代码的类的情况,也就是你的类代码和你扩展的源码是同时编译的情况下。

类扩展的方法和上面的分类类似,他们不需要写扩展分类的名称,这个有点像匿名扩展分类的概念了,如下所示

@interface ClassName ()

@end

这个匿名的扩展分类,和普通的Category不同,它除了可以方法外,还可以添加属性或者变量的。

2、协议Protocal

这个概念有很大程度上和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#是多个接口)的情况。

从C#到Objective-C,循序渐进学习苹果开发(3)--分类(category)和协议Protocal的理解的更多相关文章

  1. 从C#到Objective-C,循序渐进学习苹果开发(4)--代码块(block)和错误异常处理的理解

    本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.本文继续上一篇随笔<从 ...

  2. 从C#到Objective-C,循序渐进学习苹果开发(2)--Objective-C和C#的差异

    本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台开发苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验. 在上篇<从C#到 ...

  3. 从C#到Objective-C,循序渐进学习苹果开发(7)--使用FMDB对Sqlite数据库进行操作

    本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.本篇主要开始介绍基于XCod ...

  4. 从C#到Objective-C,循序渐进学习苹果开发(5)--利用XCode来进行IOS的程序开发

    本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.前面几篇随笔主要介绍C#和O ...

  5. 从C#到Objective-C,循序渐进学习苹果开发(1)--准备开发账号和开发环境

    本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验,因为一旦方方面面都精通了,也 ...

  6. 从C#到Objective-C,循序渐进学习苹果开发(6)--视图控制器的使用

    本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.本篇主要开始介绍基于XCod ...

  7. 【VS开发】循序渐进学习使用WINPCAP(一)

    winpcap教程 中文教程 http://www.ferrisxu.com/WinPcap/html/index.html 除此之外, WinPcap · Developer Resources下载 ...

  8. 【零基础学习iOS开发】【转载】

    原文地址:http://www.cnblogs.com/mjios/archive/2013/04/24/3039357.html 本文目录 一.什么是iOS 二.主流手机操作系统 三.什么是iOS开 ...

  9. 10 个学习iOS开发的最佳网站(转)

    10 个学习iOS开发的最佳网站 作者 jopen 2012-09-26 08:59:56 1) Apple Learning Objective C Objective-C,通常写作ObjC和较少用 ...

随机推荐

  1. 冲刺阶段day7

    day7 项目进展 又是一个周三,有轮到我写东西了.首先我们对昨天的成果调试了几遍,改了几个小Bug之后就没有什么问题了,完善了登录界面的代码,学生管理这部分终于被敲定下来,并且正式完工了.然后还生下 ...

  2. web前端职业规划(转)

    关于一个WEB前端的职业规划,其实是有各种的答案,没有哪种答案是完全正确的,全凭自己的选择,只要是自己选定了, 坚持去认真走,就好.在这里,我只是简要说一下自己对于这块儿内容的理解.有一个观点想要分享 ...

  3. zendframework 2 链接数据库

    相对于zf1,来说,zf2让我们对于数据库这方面的操作我的个人感觉是对于字段起别名简单了,但是对数据库的操作虽然配置写好的就基本不需要动了,但是还是比1的配置要繁琐, 还是那句话,大家可以去看看源码. ...

  4. 三天学会HTML5——SVG和Canvas的使用

    在第一天学习了HTML5的一些非常重要的基本知识,今天将进行更深层学习 首先来回顾第一天学习的内容,第一天学习了新标签,新控件,验证功能,应用缓存等内容. 第2天将学习如何使用Canvas 和使用SV ...

  5. Atitit usrQBK1600 技术文档的规范标准化解决方案

    Atitit usrQBK1600 技术文档的规范标准化解决方案 1.1. Keyword关键词..展关键词,横向拓展比较,纵向抽象细化拓展知识点1 1.2. 标题必须有高大上词汇,参考文章排行榜,1 ...

  6. paip. 解决php 以及 python 连接access无效的参数量。参数不足,期待是 1”的错误

    paip. 解决php 以及 python 连接access无效的参数量.参数不足,期待是 1"的错误 作者Attilax  艾龙,  EMAIL:1466519819@qq.com  来源 ...

  7. salesforce 零基础学习(三十二)通过Streams和DOM方式读写XML

    有的时候我们需要对XML进行读写操作,常用的XML操作主要有Streams和DOM方式. 一.Streams方式 Streams常用到的类主要有两个XmlStreamReader 以及XmlStrea ...

  8. ASP.NET MVC 异常Exception拦截器Fillter

    异常信息的处理在程序中非常重要, 在asp.net mvc中提供异常属性拦截器进行对异常信息的处理,异常拦截器也没有什么的,只是写一个类,继承另一个类(System.Web.Mvc.FilterAtt ...

  9. chrome远程调试真机上的app - 只显示空白页面

    chrome远程调试真机上的app - 只显示空白页面 这个是chrome需要的插件没办法自动下载导致的,怎么办你懂得,越狱... 调试起来感觉卡顿的厉害哇,有没有更好的方式?

  10. js在控件原有的事件方法中加入自己的方法

    有没有碰到过这样的情况,在一个别人的页面上,你想为某个按钮加入自己的控制逻辑,满足条件的情况下才执行原有的事件方法呢? 这个时候在不能修改其原有方法的情况下,先获取控件的事件方法,并将其包装到自己的控 ...