OC Protocol(待续)

5 篇文章 0 订阅

Protocol

协议声明任何类都可以选择实现的编程接口。协议使得两个通过继承而远近相关的类可以相互通信以实现某个目标。因此,它们提供了一种替代子类化的方法。任何可以提供对其他类有用的行为的类都可以声明一个编程接口,以匿名方式提供该行为。任何其他类都可以选择采用协议并实现其一个或多个方法,从而利用该行为。如果协议采纳者实现了协议中的方法,则声明协议的类将调用这些方法。

在这里插入图片描述

其实OC中的Protocol跟Java中的Interface是非常相似的。

Formal and Informal Protocols

有正式和非正式两种:

  • 一个正式的协议声明了客户classes期望实现的方法列表。正式协议有自己的声明、adoption和类型检查语法。可以使用@required和@optional关键字指定实现为必需或可选的方法。子类继承其祖先采用的形式协议。正式协议也可以采用其他协议。形式协议是Objective-C语言的扩展。
  • 非正式协议是关于NSObject的一个category,它隐含地使几乎所有对象都采用该协议。(category是一种语言特性,它使您能够向类中添加方法而不必将其子类化。)在非正式协议中实现这些方法是可选的。在调用方法之前,调用对象检查目标对象是否实现了它。在Objective-c2.0中引入可选协议方法之前,非正式协议对于Foundation和AppKit类实现委托的方式至关重要。

Adopting and Conforming to a Formal Protocol

类可以声明采用正式协议,也可以从超类继承采用。采用语法在类的@interface声明中使用尖括号。在下面的示例中,CAAnimation类将其超类声明为NSObject,然后正式采用三种协议。

@interface CAAnimation : NSObject <NSCopying, CAMediaTiming, CAAction>

如果一个类采用了一个协议或继承了另一个采用该协议的类,则该类及其任何实例都被称为符合正式协议。与协议的一致性还意味着类实现了协议的所有必需方法。您可以在运行时通过发送conformsToProtocol:message来确定对象是否符合协议。

Working with Protocols

在现实世界中,公务人员在处理某些情况时往往需要遵循严格的程序。例如,执法人员在进行调查或收集证据时,必须“遵守协议”。
在面向对象编程的世界中,能够定义一组对象在给定情况下预期的行为是很重要的。例如,表视图希望能够与数据源对象通信,以便找出需要显示的内容。这意味着数据源必须响应表视图可能发送的一组特定消息。

数据源可以是任何类的实例,例如视图控制器(在OS X上是NSViewController的子类,在iOS上是UIViewController的子类)或者可能只是从NSObject继承的专用数据源类。为了让表视图知道对象是否适合作为数据源,必须能够声明该对象实现了必要的方法。

Objective-C允许您定义协议,这些协议声明特定情况下预期使用的方法。本章描述了定义正式协议的语法,并解释了如何将类接口标记为符合协议,这意味着类必须实现所需的方法。

Protocols Define Messaging Contracts

类接口声明与该类关联的方法和属性。相反,协议用于声明独立于任何特定类的方法和属性。

定义协议的基本语法如下:

@protocol ProtocolName
// list of methods and properties
@end

协议可以包括实例方法和类方法以及属性的声明。例如,考虑一个用于显示饼图的自定义视图类,如图5-1所示。

在这里插入图片描述

为了使视图尽可能地可重用,关于信息的所有决策都应该留给另一个对象,即数据源。这意味着同一视图类的多个实例可以通过与不同的源通信来显示不同的信息。

饼图视图所需的最少信息包括段的数量、每个段的相对大小以及每个段的标题。因此,饼图的数据源协议可能如下所示:

@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
@end

注意:此协议将NSUInteger值用于无符号整数标量值。下一章将更详细地讨论这种类型。

饼图视图类接口需要一个属性来跟踪数据源对象。这个对象可以是任何类,所以基本属性类型将是id。关于这个对象唯一已知的就是它符合相关协议。声明视图的数据源属性的语法如下所示:

@interface XYZPieChartView : UIView
@property (weak) id <XYZPieChartViewDataSource> dataSource;
...
@end

Objective-C使用尖括号表示与协议的一致性。此示例为符合XYZPieChartViewDataSource协议的通用对象指针声明弱属性。

通过在属性上指定所需的协议一致性,如果试图将属性设置为不符合协议的对象,即使基本属性类类型是泛型的,也会收到编译器警告。对象是UIViewController还是NSObject的实例并不重要。重要的是它符合协议,这意味着饼图视图知道它可以请求它需要的信息。

Protocols Can Have Optional Methods

默认情况下,协议中声明的所有方法都是必需的方法。这意味着任何符合协议的类都必须实现这些方法。

也可以在协议中指定optional方法。如果只需要一个类就可以实现这些方法。

例如,您可能决定饼图上的标题应该是可选的。如果数据源对象未实现titleForSegmentAtIndex:,则视图中不应显示标题。

可以使用@optional指令将协议方法标记为可选,如下所示:

@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
@optional
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
@end

在本例中,只有titleForSegmentAtIndex:方法被标记为可选。前面的方法没有指令,因此假定是必需的。@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

Check that Optional Methods Are Implemented at Runtime

如果协议中的某个方法标记为可选,则在尝试调用该方法之前,必须检查该对象是否实现了该方法。例如,饼图视图可以测试段标题方法,如下所示:

NSString *thisSegmentTitle;
    if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) {
        thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
    }

respondsToSelector:方法使用选择器,它是指编译后方法的标识符。通过使用@selector()指令并指定方法的名称,可以提供正确的标识符。

如果本例中的数据源实现了该方法,则使用标题;否则,标题保持为零。

记住:局部对象变量会自动初始化为nil

如果您试图在符合上面定义的协议的id上调用respondsToSelector:方法,您将得到一个编译器错误,即没有已知的实例方法。一旦您用协议限定了一个id,所有静态类型检查都会返回;如果您试图调用任何未在指定协议中定义的方法,就会得到一个错误。避免编译器错误的一种方法是将自定义协议设置为采用NSObject协议。

Protocols Inherit from Other Protocols

当我们在使用portocol的时候,可以从别的protocol来继承相应的文件。与Objective-C类可以从超类继承一样,您也可以指定一个协议与另一个协议一致。例如,最好将协议定义为符合NSObject协议(一些NSObject行为从其类接口分离到一个单独的协议;NSObject类采用NSObject协议)。

通过指明您自己的协议符合NSObject协议,您表示采用定制协议的任何对象也将为每个NSObject协议方法提供实现。因为您可能正在使用NSObject的某些子类,所以不必担心为这些NSObject方法提供自己的实现。然而,对于上述情况,采用议定书是有用的。

要指定一个协议与另一个协议一致,请在尖括号中提供另一个协议的名称,如下所示:

@protocol MyProtocol <NSObject>
...
@end

在这个例子中,采用MyProtocol的任何对象也有效地采用了NSObject协议中声明的所有方法。

Conforming To Protocol

表示类采用协议的语法再次使用尖括号,如下所示

@interface MyClass : NSObject <MyProtocol>
...
@end

这意味着MyClass的任何实例都将不仅响应接口中特别声明的方法,而且MyClass还提供MyProtocol中所需方法的实现。不需要在类接口中重新声明协议方法,采用协议就足够了。

注意:编译器不会自动合成采用的协议中声明的属性。

如果需要一个类采用多个协议,可以将它们指定为逗号分隔列表,如下所示:

@interface MyClass : NSObject <MyProtocol, AnotherProtocol, YetAnotherProtocol>
...
@end

提示:如果您发现自己在一个类中采用了大量的协议,这可能表明您需要通过将必要的行为拆分到多个较小的类(每个类都有明确定义的职责)来重构过于复杂的类。
对于新的OS X和iOS开发人员来说,一个相对常见的陷阱是使用单一的应用程序Protocol类来包含应用程序的大部分功能(管理底层数据结构、为多个用户界面元素提供数据以及响应手势和其他用户交互)。随着复杂性的增加,类变得更难维护。

一旦指明了与协议的一致性,该类必须至少为每个必需的协议方法提供方法实现,以及您选择的任何可选方法。如果您未能实现任何必需的方法,编译器将警告您。

注意:协议中的方法声明和其他声明一样。实现中的方法名和参数类型必须与协议中的声明匹配。

Cocoa and Cocoa Touch Define a Large Number of Protocols

Cocoa和Cocoa Touch对象在各种不同的情况下使用协议。例如,表视图类(用于OS X的NSTableView和用于iOS的UITableView)都使用数据源对象为它们提供必要的信息。两者都定义了自己的数据源协议,其使用方式与上面的xyzpiechartviewdatasourceprotocol示例基本相同。这两个表视图类还允许您设置委托对象,该对象必须再次符合相关的NSTableViewDelegate或UITableViewDelegate协议。委托负责处理用户交互,或自定义某些条目的显示。

有些协议用于指示类之间的非层次相似性。一些协议不是与特定的类需求相联系,而是与更一般的Cocoa或Cocoa-Touch通信机制相关,这些机制可能被多个不相关的类采用。

例如,许多框架模型对象(如NSArray和NSDictionary之类的集合类)支持NSCoding协议,这意味着它们可以对其属性进行编码和解码,以便作为原始数据进行存档或分发。NSCoding使得将整个对象图写到磁盘上相对容易,只要图中的每个对象都采用协议。

Protocols Are Used for Anonymity

在对象的类未知或需要隐藏的情况下,协议也很有用。例如,框架的开发人员可以选择不发布框架中某个类的接口。因为类名未知,所以框架的用户不可能直接创建该类的实例。相反,框架中的其他对象通常会被指定为返回现成的实例,如下所示:

 id utility = [frameworkObject anonymousUtility];

为了使这个anonymousUtility对象有用,框架的开发人员可以发布一个协议来揭示它的一些方法。即使没有提供原始的类接口(这意味着类保持匿名),对象仍然可以有限的方式使用:

id <XYZFrameworkUtility> utility = [frameworkObject anonymousUtility];

例如,如果您正在编写一个使用核心数据框架的iOS应用程序,那么很可能会遇到NSFetchedResultsController类。这个类的设计目的是帮助数据源对象向iosuitableview提供存储的数据,从而可以轻松地提供行数等信息。

如果您使用的表视图的内容被拆分为多个部分,您还可以向fetch results vc请求相关的节信息。NSFetchedResultsController类不是返回包含此节信息的特定类,而是返回一个符合NSFetchedResultsSectionInfo协议的匿名对象。这意味着仍然可以查询对象以获取所需的信息,例如节中的行数:

NSInteger sectionNumber = ...
    id <NSFetchedResultsSectionInfo> sectionInfo =
            [self.fetchedResultsController.sections objectAtIndex:sectionNumber];
    NSInteger numberOfRowsInSection = [sectionInfo numberOfObjects];

即使您不知道sectionInfo对象的类,NSFetchedResultsSectionInfo协议规定它可以响应numberOfObjects消息。

欢迎使用Markdown编辑器

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值