题 使Objective-C类看起来很漂亮


我想问你所有关于Objective C中代码味道的意见,特别是Cocoa Touch。我正在制作一个相当复杂的游戏,即将开始伟大的十二月重构。

我的很多课程,尤其是模型,都充满了处理内部业务逻辑的方法;在我对抗大量头文件的战争中,我将隐藏在私人类别中。那些私人类别包含大量的声明,这让我感到不安......就像Objective-C一样让我对所有这些方法感到内疚。

我重构的越多(一件好事!),我就越需要保持所有这些重复(不太好)。这只是感觉不对。

在像Ruby这样的语言中,社区强调非常简短,清晰,美观的方法。我的问题是,对于Objective C(特别是Cocoa Touch),您的方法有多长,控制器有多大,每个类的方法在您的项目中都是典型的?是否有任何特别漂亮,漂亮的课程由Objective C中的简短方法组成,或者它根本不是语言文化的重要组成部分?

披露:我正在阅读“The Little Schemer”,这应该解释我的悲伤,重新:目标C.


37
2017-12-09 06:27


起源


+1很棒的问题! - Rog
谢谢!很明显,当我开始考虑回答obj-c问题需要多长时间而不是ruby问题时,这是一个严重的问题。格儿... - Sam Ritchie
你可能对此感兴趣 堆栈交换提案。它几乎准备好开始测试,只需要更多。 - greatwolf
维克多,非常感谢,看起来很棒。我现在正在学习Clojure,而且根本没有其他人可以查看工作。我刚才承诺了! - Sam Ritchie


答案:


美女 是主观的。对我来说,如果Objective-C类是可读的(我知道它应该做什么)并且可维护(我可以看到哪些部分负责做什么),它就很漂亮了。我也不喜欢被一个不熟悉的习语抛弃阅读代码。有点像你正在读书的时候,你会读到让你沉浸其中的东西并提醒你正在阅读。

你可能会得到很多不同的,互相排斥的建议,但这是我的想法。

  • 私有方法属于私有类别没有错。这就是它的用途。如果您不喜欢堵塞文件的声明,请在IDE中使用代码折叠,或将扩展作为类别放在不同的文件中。
  • 将相关方法组合在一起并用它们标记 #pragma mark 声明
  • 无论您使用何种代码布局,一致性都很重要。花几分钟时间写下你自己的指导原则(这里是 )所以,如果你忘了你应该做的事,你就有了参考。
  • 控制器不必是委托和数据源,您可以始终拥有其他类。
  • 对方法和属性使用描述性名称。是的,您可以记录它们,但是当Xcode应用代码完成时,您无法看到文档,其中命名良好的方法和属性得到了回报。此外,如果在代码本身更改时未更新代码注释,则代码注释会过时。
  • 不要试着写出聪明的代码。您可能认为最好将一系列方法调用链接到一行,但编译器在优化方面比您想象的要好。如果提高可读性,可以使用临时变量来保存值(大多数这些只是指针,所以相对较小)。 编写供人阅读的代码
  • DRY与其他语言一样适用于Objective-C。不要担心将代码重构为更多方法。只要它们有用,有很多方法没有错。

15
2017-12-09 11:47



我已经放弃了 #pragma mark 赞成 // MARK: 它对Xcode中的菜单有相同的效果,但不会在编译器之间可移植的代码中引起警告。也, // MARK: -  是一个真正的帮助(也与pragma一起工作)。它在菜单中放置了一个水平规则。 - JeremyP
多亏了这一点,这些都很棒,并且在伟大的重构过程中非常方便。 - Sam Ritchie


在实现类或方法之前我做的第一件事就是问: “我怎么想从外面使用它?”

我从来没有, 决不 首先编写我的类和方法的内部。通过优雅的公共API开始,内部趋向于优雅免费,如果他们不这样,那么丑陋至少包含在单个方法或类中,并且不允许用其气味污染其余代码。

有许多设计模式,二十年的编码告诉我,经得起时间考验的唯一模式是: 。保持简单愚蠢。

对于任何语言或环境,一些一般的经验法则:

  • 跟随你对你读过或听过的任何建议的直觉!
  • 早退!
    • 如果需要,请尽早验证输入并快速拯救!减少清理工作。
  • 切勿在代码中添加不使用的内容。
    • 一个选项 “相反” 在路上可能会感觉很愉快。
    • 在那种情况下,将它添加到路上!不要浪费时间增加你不需要的复杂性。
  • 方法名称应描述所做的事情, 决不 怎么做。
    • 只要结果相同,应允许方法更改其实现而不更改其名称。
    • 如果您无法从其名称中了解方法的作用,请更改名称!
    • 如果部分足够复杂,那么使用注释来描述您的实现。
  • 不要害怕单身人士!
    • 如果您的应用只有一个数据模型,那么它就是一个单例!
    • 在整个地方传递一个变量只是假装它只是一个单身,并增加复杂性作为奖励。
  • 从一开始就计划失败。
    • 总是用来做 doFoo:error 代替 doFoo: 从头开始。
    • 创造美好 NSError 从一开始就具有最终用户可读本地化描述的实例。
    • 将错误处理/消息改装到大型现有应用程序是一个很大的痛苦。
    • 如果您涉及用户和IO,将始终存在错误!
  • Cocoa / Objective-C是 Object * Oriented,而不是** Class 面向大多数流行的孩子,声称是OOP。
    • 不要仅使用属性引入哑值类,没有执行实际工作的方法的类也可以是结构。
    • 让你的对象变得聪明!为什么要添加一个全新的 FooParser 如果一个班级 fooFromString: 方法 Foo 是你所需要的全部?
  • 在可可你是什么 可以做 永远比重要的更重要 你是什​​么
    • 如果目标/操作可以执行,请不要引入协议。
    • 不要验证实例是否符合协议,是一种由编译器决定的类。

7
2017-12-12 11:44



Apple喜欢仅比例的类比结构(抱歉,没有参考)。还有,内省 能够 在处理时很有用 id,子类或可选的协议方法。 - Scott Berrevoets
@Scott - Jupp,这是ARC介绍后的变化。 ARC不能在结构中使用对象引用,但可以使用类。 - PeyloW
完全同意这一点,总结我的经验:) - theLastNightTrain


我的2美分:

  1. 属性 通常比旧式的getter + setter更好。即使您使用@dynamic属性 - 使用@property声明它们,这也会提供更多信息和更短的信息。
  2. 我个人 不要模拟“私人”方法 对于课程。是的,我可以在.m(m)文件中的某个地方写一个类别,但是因为Obj-C没有纯粹的方法来声明私有方法 - 我为什么要发明一个呢?无论如何,即使你真的需要这样的东西 - 用类别声明一个单独的“MyClassPrivate.h”并将其包含在.m(m)文件中以避免重复声明。
  3. 捆绑。绑定大多数Controller < - > UI关系,使用变换器,格式化器,只是不要编写方法来手动读/写控制值。它使代码看起来像MFC时代的东西。
  4. C ++,用C ++编写时,很多代码看起来更好更短。由于编译器理解C ++类,因此重构是一个很好的观点,特别是在工作时会使用低级代码。
  5. 我经常拆分大型控制器。某物 超过500行代码 对我来说,重构是一个很好的选择。例如,我有一个文档窗口控制器,因为它的某些版本的应用程序扩展了图像导入/导出选项。控制器增长到1.000行,其中1/2是“图像填充”。这是我制作ImageStuffController的“触发器”,在NIB中实例化它并将所有与图像相关的代码放在那里。

以上所有内容使我更容易维护我的代码。对于一个巨大的项目,分割控制器和类以保持小的结果大量的文件,我通常尝试将一些代码提取到框架中。例如,如果应用程序的很大一部分与外部Web服务进行通信,则通常可以通过主应用程序直接提取MyWebServices.framework。


2
2017-12-09 11:24



#4是一个可怕的,可怕的想法。我第一次听到有人说要翻译成C ++以使代码看起来更好。 - Jon Shier
例如,jshier,C ++允许为NSPoint定义一个+运算符。对我来说,p1 + p2看起来比NSOffsetPoint(p1,p2)更好。使用地图和列表等数据结构时,C ++更加清晰(除非结果直接用于UI - 这就是你应该使用NS-classes的地方)。接下来 - 数学任务。用于matricies和vector的C ++库通常比NSAffineTransform和其他更容易使用。使用NSGraphicsContext时,NS-classes再次出色,但是一些后端数学肯定应该用C ++处理以简化代码。恕我直言,当然 - Gobra