Objective-C官方文档 协议
版权声明:原创作品,谢绝转载!否则将追究法律责任。
在现实生活中,当处理某一情况的时候人们往往遵循严格的程序。执法人员他们在打官司的收集证据和询问的时候一定要遵守协议。
在面向对象的语言中,最重要的是一个对象需要定义一些行为在某种情况下。例如:一个tableView希望能够和数据源交互目的是为了表明他要展示什么数据。这意味着数据必须回应tableView一组特殊的消息。
这个数据源可能是一些类的实例,例如一个Controller或者一个专门继承NSObject类的数据源类为了让tableView知道这个对象适不适合做这个数据源,所以必须声明的是让这个对象实现必须的方法。
Objective-c允许你定义协议,表明这个方法希望用在特殊的情况。这章的主要内容描述了定义一个标准协议的语法,并且声明一个类接口来遵守这个协议,这意味着这个类必须实现他需要实现的方法。
协议定义消息传递的规则:
一个类的接口声明了和这个类关联的属性和方法。协议和之前定义类接口相比,被用来声明方法和属性是为了一些特定的类。
声明协议的基本语法:
@protocol ProtocolName
// list of methods and properties
@end
协议可以包含类方法实例方法和属性的声明:
例如一个自定义View类用来展示饼状图如下图:
为了使这个View可能的重复利用,所有的决策信息应该留给另一个对象,一个数据源。这意味着多个实例相同的视图类,可能展示不同的信息通过和不同的数据源进行交互。
这个最低的信息需要包括这个饼图包含几个部分,每个部分的相对大小,并且每个部分的标题。因此这个饼图的协议方法大概包含以下几个不分:
@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
@end
注意:这个协议用无符号整形来定义标量值,后面章节会详细讨论。
这个饼图视图类将要需要一个属性来跟踪数据源对象。这个对象可以是任何类,因此这个属性的类型是id类型。唯一知道这个对象的信息是他符合相关的协议。
这个在View里面定义数据源的属性像这样:
@interface XYZPieChartView : UIView
@property (weak) id <XYZPieChartViewDataSource> dataSource;
...
@end
Objective-c用尖括号表示符合这个协议。这个例子声明了一个弱引用类型通用类型的对象指针并且符合XYZPieChartViewDataSource。
注意:代理和数据源的属性被声明弱引用类型的原因是避免强引用的循环。
通过给属性指定相关的协议,你将要得到一个警告如果你设置的这个对象的属性不符合这个协议,尽管这个属性的类型是通用类型的。不要担心这个实例对象是UIViewController还是NSObject。最重要的是他符合这个协议,意味着这个饼图知道他可以请求需要的数据。
协议可以有可选的方法:
默认情况下协议声明下的方法都是必须实现的方法。这意味着任何类遵守这个协议必须实现他的这些方法。
你也可以声明可选的方法在协议里面。这些方法是某些类选择实现的。
例如你可以决定这个显示饼图标题的这个协议方法是可选的。如果这个数据源对象不实现这个可选的方法。那么就没有标题显示在饼图上。我们可以如下声明可选的协议方法:
@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
@optional
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
@end
在这个例子中只有后面这个方法是可选的。之前的那些方法没有说明因此默认还是必须实现的。
这个@optional指令适合任何方法遵循他,要么直到最后协议的定义,或者到另一个指令的声明例如@required例如:
@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
@optional
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
- (BOOL)shouldExplodeSegmentAtIndex:(NSUInteger)segmentIndex;
@required
- (UIColor *)colorForSegmentAtIndex:(NSUInteger)segmentIndex;
@end
这个例子定义了三个必须实现的方法还有两个可选的方法。
确保可选方法是在运行时被实现的:
如果这个协议方法是可选的你必须检查这个对象是否实现了这个方法再调用他。例如:这个饼图可能这样测试这个方法:
NSString *thisSegmentTitle;
if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) {
thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
}
这个respondsToSelector:方法使用一个选择器,他指的是一个方法编译后的标识符,你能提供正确的标识符通过使用@selector()指令和指定的方法名称。
如果这个数据源在这个例子中实现这个方法,这个标题就出现,否则这个标题是空的。
注意:局部变量默认初始化为nil。
如果你试图调用了未定义在特殊协议里面的方法,那么你就会得到一个恶错误。为了避免这个编译错误你需要设置你的自定义协议采用NSObject协议。
协议是可以继承其他的协议的:
就像一个Objective-c类可以继承其他的父类一样,你可以指定一个协议符合另一个协议。
例如一个最好的实践定义你的协议符合NSObject协议(一些NSObject行为从其类接口中分离到一个单独的协议文件里)NSObject类是采用NSObject协议的。
通过表明你自己的协议符合NSObject的协议来表明任何对象采用自定义协议还将提供NSObject协议的方法。因为你可能用NSObject的一些子类,你不要为这些NSObject协议方法提供实现而担心。该协议提供是有用的就像上面描述的那样。
指定一个协议符合另一个协议,你需要在尖括号里提供另一个协议的名字就像这样:
@protocol MyProtocol <NSObject>
...
@end
在这个例子中任何采用自定义协议同样也能使用NSObject协议的方法。
符合协议:
声明一个类符合协议需要在尖括号里写上协议的名字像这样:
@interface MyClass : NSObject <MyProtocol>
...
@end
这意味着MyClass的实例不仅仅能响应自己在接口定义的方法,而且这个MyClass也提供在myProtocol必选的方法的实现。没有必要重新声明这些方法在接口文件里,采用协议是足够的。
如果你需要一个类采用多个协议,你可以指定他们作为一个以逗号分隔的列表像这样:
@interface MyClass : NSObject <MyProtocol, AnotherProtocol, YetAnotherProtocol>
...
@end
技巧:如果发现你自己符合了很多协议在类里面,这可能意味着你可能需要重构那些过去复杂的类,分裂了必须的行为在很多小类,每个都有清晰的责任。
一个相对新的OSX操作系统普遍存在的缺陷和IOS开发是使用一个应用程序委托类包含大多数应用程序的功能(管理底层数据结构,服务数据到多个用户界面元素,以及响应手势和其他用户交互)。随着复杂性的增加,类变的更难维护。
一旦你已经声明符合某个协议,这个类必须最少提供协议要必须实现方法的实现,以及任何你选的可选方法,这个编译器将要警告你如果你没有实现必须实现的方法。
注意:这个定义在协议里面的方法就像定义在接口里面的方法一样。这个方法的名字和参数类型在实现的时候必须和在协议里面定义的一样。
cocoa和cocoa touch定义了大量的协议
协议被cocoa和cocoatouch对象在很多不同的环境中使用。例如,tableView类即用数据源对象来提供他需要的信息。也定义了自己的数据源协议。tableView的类允许你设置委托对象,必须符合UITableViewDelegate协议,这个代理的责任负责处理用户交互或者定制显示的某些条目。
一些协议用于表示类之间的相似性。而不是与特定类的需求,一些协议相反与更普遍的cocoa或者cocoa touch沟通联系机制,可以采用多个不相关的类。
例如一些框架数据对象像集合对象NSArray和NSDictionay支持NSCoding协议,这意味着他可以编解码给他们的属性为了存档或者发布作为原始数据。NSCoding使把对象写入磁盘变的更容易,这些对象符合这个协议。
一些Objective-c的低级特性也依靠协议。为了使用快速枚举,例如,一个集合必须符合NSFastEnumeration协议,就像在Fast Enumeration Makes it East to Enumerate a Collection。此外,一些对象可以被copy,例如当用属性的copy关键字的时候,这些对象必须符合NSCopying协议,否则你将要在运行时得到一个异常。
协议都是匿名的
协议也可以在对象不确定的情况使用,或者需要隐藏。
例如一个框架的开发者可能选择不公布某些类的接口。因为这些类名字不知道,用这个框架的人不可能直接创建这个类的实例。相反的一些在框架的对象被典型的设计为返回一个创建好的实例对象。像这样:
id utility = [frameworkObject anonymousUtility];
为了使anonymousUtility对象更有用,这个框架开发者公布了协议的某些方法。尽管原始类的接口没有被提供。这意味着类保持匿名,对象仍然可以被使用在一个有限的方式:
id <XYZFrameworkUtility> utility = [frameworkObject anonymousUtility];
如果你写IOS的应用用core Data框架,例如你可能会遇到NSFetchedResultsController类。这个类帮助datasource对象为tableView提供存储数据,使他更容易提供行数的信息。
如果你能用到tableView的多个分区,你也可以得到一些分区信息的结果。而不是返回一个特定的类包含分区信息,NSFetchedResultsController返回一个匿名对象,这个匿名对象符合NSFetchedResultsSectionInfo协议。这意味着他仍然可以查询对象为你需要的信息,比如一个分区多少行:
NSInteger sectionNumber = ...
id <NSFetchedResultsSectionInfo> sectionInfo =
[self.fetchedResultsController.sections objectAtIndex:sectionNumber];
NSInteger numberOfRowsInSection = [sectionInfo numberOfObjects];
尽管你不知道sectionInfo 对象,NSFetchedResultsSectionInfo 协议表明他仍然可以响应numberOfObjects方法。
Objective-C官方文档 协议的更多相关文章
- gRPC官方文档(通讯协议)
文章来自gRPC 官方文档中文版 HTTP2 协议上的 gRPC 本文档作为 gRPC 在 HTTP2 草案17框架上的实现的详细描述,假设你已经熟悉 HTTP2 的规范.产品规则采用的是ABNF 语 ...
- Spring 4 官方文档学习 Spring与Java EE技术的集成
本部分覆盖了以下内容: Chapter 28, Remoting and web services using Spring -- 使用Spring进行远程和web服务 Chapter 29, Ent ...
- Spring 4 官方文档学习(十四)WebSocket支持
个人提示:如果需要用到页面推送,高频且要低延迟,WebSocket无疑是最佳选择.否则还是轮询和long polling吧. 做了一个小demo放在码云上,有兴趣的可以看一下,简单易懂:websock ...
- OC-苹果官方文档
苹果官方文档 help>documentation>左边iOS>language>objective>the objective-c programming langua ...
- clang format 官方文档自定义参数介绍(中英文)
官方文档:http://clang.llvm.org/docs/ClangFormatStyleOptions.html 中文 在代码中配置样式 当使用 clang::format::reformat ...
- 自己翻译 delegation 官方文档
什么是代理,知道怎么用,见过N次.会用代理传值,还不够.代理到底是用来干嘛的嘛?还是看看官方文档吧,自己翻译出来看看是不是通顺 代理: 代理是一个简单高效的模式,尤其是一个类在编程的过程中代表或者需要 ...
- spring官方文档中文版
转 http://blog.csdn.net/tangtong1/article/details/51326887 spring官方文档:http://docs.spring.io/spring/do ...
- ios学习笔记第四天之官方文档总结
start developing ios app today. 官方文档的体系结构为: 各层的主要框架图: objectice-c是动态语言 Objective-C 为 ANSI C 添加了下述语法和 ...
- Spring Cloud官方文档中文版-服务发现:Eureka服务端
官方文档地址为:http://cloud.spring.io/spring-cloud-static/Dalston.SR3/#spring-cloud-eureka-server 文中例子我做了一些 ...
随机推荐
- unity-------------------打包BuildAssetBundles的使用
unity5打包机制下,一种资源打ab和资源管理的方案.1.打ab: 1.设置平台 2.清楚所有资源的assetbundlename: string[] abNameArr = AssetDataba ...
- 下拉刷新XListView的简单分析
依照这篇博文里的思路分析和理解的 先要理解Scroller,看过的博文: http://ipjmc.iteye.com/blog/1615828 http://blog.csdn.net/wangji ...
- 监听事件绑定(addEventListener、attachEvent)和移除(removeEventListener、detachEvent)
/** * @description 事件绑定,兼容各浏览器 * @param target 事件触发对象 * @param type 事件 * @param func 事件处理函数 */ funct ...
- vue加百度统计代码(亲测有效)
申请百度统计后,会得到一段JS代码,需要插入到每个网页中去,在Vue.js项目首先想到的可能就是,把统计代码插入到index.html入口文件中,这样就全局插入,每个页面就都有了;这样做就涉及到一个问 ...
- vue-router2路由参数注意问题
1.vue 路由 如果传递 params 定义路由的时候是 /路由名称:id 获取的时候 this.$route.params.id 最后形如 /路由名称/路由参数 传参的时候 params:{ st ...
- Mapper method 'com.autoyol.mapper.trans.AccountLogMapper.getTotalIncomByMemNoLastest attempted to return null from a method with a primitive return type (int).解决方法
1.打开日志输出,降低日志级别. <AppenderRef ref="console" level="trace"></AppenderRef ...
- 为什么调用 FragmentPagerAdapter.notifyDataSetChanged() 并不能更新其 Fragment?【转载】
转载自:http://www.cnblogs.com/dancefire/archive/2013/01/02/why-notifyDataSetChanged-does-not-work.html ...
- MySQL 高性能表设计规范
良好的逻辑设计和物理设计是高性能的基石, 应该根据系统将要执行的查询语句来设计schema, 这往往需要权衡各种因素. 一.选择优化的数据类型 MySQL支持的数据类型非常多, 选择正确的数据类型对于 ...
- Android和IOS开发学习路线
图片看上去太小,直接另存为吧 图片来自:http://www.finalshares.com/
- SpringMVC由浅入深day01_13springmvc和struts2的区别_14问题
13 springmvc和struts2的区别 1.springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发, ...