些上下文的帮助。
一些你可能没有预料到的其它情况。 高亮当然是 代理中的 optional方法组中的一个例子,但它非常重要值得拥有,并且常常只要小量工作既可实现。
1 |
- (void)tileMenu:(MGTileMenuController *)tileMenu didSelectTile:(NSInteger)tileNumber; |
2 |
- (void)tileMenu:(MGTileMenuController *)tileMenu didDeselectTile:(NSInteger)tileNumber; |
Rule 18: 可选的方法不是一个保证
我们大部分人都把可选的委托方法当做二选一的情形:如果你不实现他们,就使用默认的行为;如果你要实现他们,那你就要为将发生的事情全部负责。那不是理想的事情。
在任何的提供一个可选的委托方法的实现中,你应该仍然返回去默认的行为,即使这个方法已经被实现了,但不要返回一些明显的东西。这听起来很明显,但是令人惊讶到底有多少组件无忧无虑地然后委托对象返回任何类型没有经过精细检查的愚蠢东西,仅仅是因为这委托莫名奇妙地答应通过实现这个方法来管理自己的行为。
我要具体地讨论下可视化的定制,如背景颜色和图片。非常非常仔细地考虑下,你是否不应该去干涉那种情况,同时依靠于你的默认界面。他们真的不想展示些东西吗?甚至让感觉好一点?它会让控制看起来很糟糕吗?如果如此,插手介入吧,同时仅在如果委托方法从来不在开始的地方就实现的时候准备默认的。
相关地,用一个有文档的、标准的及不是很突兀的方式去慎重地从每个可选的委托方法中通过返回一些如空的东西来执行默认的行为。
例如,MGTileMenu有一个比较复杂的层次方式让你可以自定义标题的背景。你可以实现三个委托方法中的任何(或者全部,或者不)方法去为每个标题提供一个背景图片、梯度或者颜色。你也能够在任何时候为任何标题选择默认的行为,通过返回空或者NULL等适当的类型。
你将不得不尝试相当困难地去使标题的背景透明(通过返回清澈的颜色或者使用空的UIImage对象)。
Rule 19 :总是说出谁正在说话
这是一个简单的规则,大家也可以同样简单地产生一个错误。在你的委托(delegate)方法中,总要传递一个sender参数。
不管是单例,还是你无法想象地将被不止一次同时使用的东西(,都应如此)。没有例外:
应当这样:
1 |
- (void)tileMenu:(MGTileMenuController *)tileMenu didActivateTile:(NSInteger)tileNumber; |
不应当这样:
1 |
- (void)tileMenuDidActivateTile:(NSInteger)tileNumber; |
Rule 20: 在查询方法中首先放置可区分的参数
一个真正的数据源协议总有将最感兴趣东西放在前边的方法。比如,你请求的指定质量或属性等。像这样:
1 |
- (UIImage *)imageForTile:(NSInteger)tileNumber inMenu:(MGTileMenuController *)tileMenu; |
不要像这样:
1 |
- (UIImage *)tileMenu:(MGTileMenuController *)tileMenu imageForTile:(NSInteger)tileNumber; |
返回类型自然而然应作为方法名的第一部分,这并不会另人奇怪(请注意上边两个函数的不同处)。数据源协议中经常有许多命名相似的方法,因此我们应该最先考虑保持函数的唯一性和感兴趣部分。这样的话,(这些方法)更容易读,更容易做到自动补全。
有人指出:Apple公司的UITableViewDataSource协议并没有按照那些做,他们是把sender放在第一位的,例如:
1 |
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section |
对此,我想说的就是:我关注这些不同之处。我坚持我的观点。
Rule 21:在通知方法中把sender放到第一位
一个真正的委托(Deletage)协议不是用来查询,而是用来通知的。在这种情况下,你应该将sender放到第一位(参考 “说出谁正在说话” 规则)。
1 |
- (void)tileMenu:(MGTileMenuController *)tileMenu willSwitchToPage:(NSInteger)pageNumber; |
这是遵循两个人交流的习惯的。你不应该跳出来就说“她将会迟到”,因为另一个会问“谁?” 取而代之,你应该说出谁正在说话。这是一个习惯,可以很方便地将查询(数据源)与通知(委托)方法区分开来。
规则 22:如果约定被打破了,那就抛开它吧!
上面已经说了这么多,记住约定和一致性一定是在某些时刻要屈服于优秀的观点的 - 在这个例子当中,或者你的例子中。如果约定被打破,那就好不担心的去跳过它。如果你的观点真的更好,那就去做吧!
举个例子,在菜单控件中已经存在一个约定了,靠这个约定你能够通过代理来使菜单选项可用或者不可用,利用calledvalidateMenuItem:方法。为了一致性的缘故,我曾考虑过给我代理协议中的一部分方法用相同的名字。但是我最终决定没有那样做,因为:
- 那是一个非常可怕的名字。“Validate”?那对我是不可用的。
- 这是必要的,在我的例子中我却是提出了一个问题。
- 我打破了我其它代理方法的命名规则。
相反的,我继续为了更简单并且更加的容易理解而打破了约定:
1 |
- (BOOL)isTileEnabled:(NSInteger)tileNumber inMenu:(MGTileMenuController *)tileMenu; |
我们能够为了特殊的语法而战,但是当你遇到那个方法时,你应该立刻就知道它是做什么的?如何来使用它。我认为,那样会更好。
通知
通知是委托协议的另一部分。我认为,如果你使用委托协议(如果合适,你应当用它),你最好加上通知,不然它不算完整。
在 MGTileMenu 中,你可以在 MGTileMenuController 的接口文件 中找到的通知。
规则 23:通知和代理方法并行
在代理方法(注意;不是数据源方法)和通知之间有一个剪不断理还乱的联系。在你的代码中同样的地方你会同时用到它们,并且起到同样的作用。
如果一个代理方法告诉代理发生了一些事情,你通常应该为了起到相同的作用发送一个通知。就像代理方法一样加上通知,去除掉模棱两可的方法,并且落实你的通知列表。
代理方法的参数应该和通知的userInfo的内容相匹配,这是很明显的