于使用,最好还是用#define或者常量或者其他的东西包装一下它们,这样会让魔数更加的直观和易于理解。
2 |
#define MG_PAGE_SWITCHING_TILE_INDEX -1 |
代理和数据源协议
代理协议是奇妙的。它们是实现MVC模式的简单的、熟悉的和灵活的方式,它们更会使你养成松耦合的好习惯并且教你明智的API设计。
这个是 MGTileMenu’s delegate protocol.
有太多经典的代理和数据源协议供我们用到几乎所有的组件中。如果你正在显示数据,这个准确的数据源协议可能更接近于:
- 我有多少事物?
- 事物X对应的属性Y的值是多少?
同样的,在几乎任何的情况中,这个准确代理协议可能采用下面的形式:
- 这个事物应该做那些嘛?
- 这个事物将要做那些。
- 这个事物刚好做了那些?
这也被称为Should, Will, Did协议模式,这也巧妙的连结了之后的Will-Did通知模式。
让我们来讨论一下你可能会觉得有争议的话题:我发现将代理协议合并到数据源协议中被完美的接受了(也就是说将他们整合到一个协议中)。我在MGTileMenu和几个其他的组件中这样做了。
我完全接受分离他们的原则,并且我能想到很多你想保持他们分离的例子。通常,苹果也是保持他们分离的。那好吧。
可是,就我的经验看,在大多数例子中合并他们是很好的。大多数人将数据源方法和代理方法放到同一个地方。我从来没有因为合并这些协议而抱怨过,我几乎不能记得一个存在分开的协议在不同的地方使用的情况。
如果你重视清晰,或者有将代理从数据源中分离出来的需求,那么很明显你应该那样做。我只是不认为如果你合并他们会觉得不好。
规则 13:限制‘required’代理方法的数量
当你选择设置哪些代理方法为required(必须实现)时一定要小心。太多的required方法将会表明:
- 可选择的默认行为非常少。
- 在代码中你自己的观点非常多。
一个精心设计的组件应该有很少很少required代理方法-仅仅是那些不得不的方法。小心选择。同样的,记住再后来添加optional(可选择实现)方法是很简单的,但是添加required方法就非常的困难(很多时候人们会抱怨)。
在MGTileMenu中有5个required方法,其中有4个是数据源方法:
1 |
- (NSInteger)numberOfTilesInMenu:(MGTileMenuController *)tileMenu; |
2 |
- (UIImage *)imageForTile:(NSInteger)tileNumber inMenu:(MGTileMenuController *)tileMenu; |
3 |
- (NSString *)labelForTile:(NSInteger)tileNumber inMenu:(MGTileMenuController *)tileMenu; |
4 |
- (NSString *)descriptionForTile:(NSInteger)tileNumber inMenu:(MGTileMenuController *)tileMenu; |
前两个属于一个真正的数据源协议。第三第四个也是,但是这也表明了我的观点:我认为软件应该是容易理解的,并且我正在强制你为每一个tile提供一个标签和表述来共读者们阅读。我很享受这些。
当然也有一个代理方法
1 |
- (void)tileMenu:(MGTileMenuController *)tileMenu didActivateTile:(NSInteger)tileNumber; |
这个方法是required,因为他告诉你如何来发现一个tile是激活状态的。如果你不打算实现这个方法,MGTileMenu将不会做任何有用的事情,甚至你可能就根本不能用它。所以他是必须实现的。
规则 14:设计成容易理解的
立刻跟上这最后的规则:使设计是容易理解的。不要在最后才注意到它,恰恰相反,应该是在起初就设计成容易理解的。如果你遵循了“在你的控件中运用控件”原则,那么你可能在不知不觉中就遵循了这个原则。
上面展示的代理(倒不如说是数据源)方法是另一个开发者为了使他们给语音辅助提供一些东西的地方。 如果你能够在视觉上(就像展示一个文本标签)自动地改变一些事情的意图就像一个语音辅助标签那样,那该多好啊(此外,在大多数例子当中语音辅助已经为你实现了这个)。
在交流方面保持清醒。做到不容易理解的设计倒是困难的。我也写了另外一篇关于在IOS应用中支持语音辅助功能的文章,这也是苹果向在容易理解的程序有联系的合伙人们推荐的。我也推荐它,但是我写它就是为了你可以接受它。
规则 15:利用语义对象来做参数
这不仅仅适用于协议,但协议是尤其重要的部分。最好是在实际应用中,用合适的语义对象作为数据,虽然在你的实现中这样做可能会更加的麻烦。
如果你需要一个日期,不要用一些数字-而应该是一个真实的日期对象。对象或者结构体可以表示每一样事物,并且你应该有意地去用它们。如果需要的话可以创建一个类(你可能不会需要)。
当然一个标准的目录除外-除了基元没有任何理由可以把他们变成任何事物,自从NSNumber的加入,对于抵消打包/非打包带来的麻烦没有任何事物是语义地足够重要的。
规则 16:如果语义不合适的话就提高API
我时刻都在注意这一点。我曾在早些时候提到过,你怎么能就像一些事物已经存在(通常,就像是已经存在了的在你的实现中无意间用到的东西)了那样考虑几乎任何新的定制的控件呢?
那非常好,并且你是很聪明的,但是不能让语义胜过相似点。为了使语义合适,在一个已经存在了的API上叠加一个新的API绝对是好的(或者漂亮的)。例如:
- 用表格实现一个联系人列表应该有一个联系人相关的API
- 用网格实现一个月份的日历试图应该有一个日期相关的API
诸如此类的等等。不要时常地强制你自己(或者其他的开发者)在抽象的实现API和真实的组件语义之间做精神上的转变 - 反而应该让这个API反映出组件真实的目的。
MGTileMenu 的代理协议通过不把菜单当做UIBUttons(实现了的)的集合而宁可说是菜单的统一做到了这一点,利用每个菜单中相关的有限的tile来展示内容。
Rule 17: 高亮是有趣的
当我不得不回过头来添加一个新的代理方法和通知到我认为已经完成了的API中,我才意识到这一点。对交互控件来说,高亮是有趣的。通过“高亮”,意味着其在应用程序中潜在的重要性。
任何控件都会通知App(在某种意义上来说,可能只是通过调用一个动作或方法),当它被完全触发时;但是当它们被高亮(选中,按住)或取消高亮被触发时,只有比较少的情况才会通知。这说明它实际上非常重要。应用程序可能需要:
- 添加,删除或重定位辅助界面。
- 更新一些其它的显示部分。
- 提供一