【问题标题】:How to avoid accidental overriding method or property in Objective-C如何避免在 Objective-C 中意外覆盖方法或属性
【发布时间】:2012-08-21 06:57:12
【问题描述】:

例如,我继承了UILabel 并添加了一个名为-verticalTextAlignment 的方法或属性来垂直对齐文本。
并且在未来,如果下一版本的 SDK 或 iOS 添加了同名的方法或属性,那么我的应用程序可能会崩溃或出现意外行为。

*即使您使用类别而不是子类,也会出现此问题。

问题1
在 Objective-C 中如何避免这种意外覆盖?
我认为您可以通过为所有方法和属性添加前缀(例如 -XXX_verticalTextAlignment)来避免这种情况。但这不太现实吧?

问题2
我知道这种意外覆盖发生在编译时或更新 iOS SDK、OSX SDK 或 XCode 时。

但是更新 iPhone 的 iOS 版本时是否也可能发生这种情况?
例如,是否有可能您的应用在 iOS5 上运行良好但在 iOS6 上由于意外覆盖而无法在 iOS6 上运行。(您可以将 iOS5 和 iOS6 替换为任何版本,例如 iOS5.0 和 iOS5.1)

【问题讨论】:

  • 您也可以有条件地加载该方法 - 请参阅我的答案。顺便说一句,+1 提出一个好问题。

标签: iphone objective-c ios


【解决方案1】:
  1. 是的,您可以使用自己的前缀,但这并不常见。

  2. 是的,它可以在操作系统更新后发生; Objective-C 是一种非常动态的语言,其中消息被发送到方法而不是像其他语言那样被调用。这些事情是在运行时解决的,而不是编译时。

底线是肯定的,您可能会不小心覆盖未来的基类方法,唯一的解决方案是在它发生时在那里并重命名该方法。

【讨论】:

  • 前缀变得越来越流行,因为 Objective C 和 Cocoa 编程越来越流行,人们对其代码的投资不允许潜在的命名空间冲突。但正如你所说,这在基础级别上并不常见。
  • @trojanfoe 谢谢。这是否意味着您必须一直担心意外覆盖,并且每次发布新的 iOS 或 OSX 版本时都必须测试所有应用程序?在那种情况下,我想为每件事加上前缀。但是你有多少次看到每个方法和属性都带有前缀的源代码? (我从未见过这样的代码。)
  • @js_ 是的,如果您真的担心它,那么前缀是您唯一的防御措施。但是,除了 library code 之外,我没有看到任何前缀用于避免与用户代码发生冲突。
  • Dave Dribbin 多年来一直在这样做:bitbucket.org/ddribin/ddfoundation 我什至称它们为“Dribbin 前缀”。在一篇博文中,他提到 Apple 从一开始就意识到了这个问题:dribin.org/dave/blog/archives/2010/03/02/what_i_miss_from_java
  • 感谢@NikolaiRuhe 和 trojanfoe 提供的良好示例和信息。我决定为所有内容添加前缀。我知道为每个方法和属性添加前缀很疯狂,但对我来说并不是很痛苦。
【解决方案2】:

为您的类别方法添加前缀是在每个不断发展的、无命名空间的可可生态系统中避免这些冲突的最安全方法。

框架创建者、开源开发者和其他个人开发者应该为他们的类方法添加前缀是非常有效和合理的。

我经常在编写方法前加上我的公司首字母缩写,然后继续使用该方法。

- (void)JCMyMethodNamedSimilarToBaseClass;

【讨论】:

  • 非常感谢!您是否不仅为category mothodsclass methods 加上前缀,而且还为子类(不是类别)的所有实例方法和属性加上前缀?并且您是否为自定义类添加前缀?(即 NSObject 的子类。因此将来可能会意外覆盖 NSObject 的方法或属性)
  • @js_ 我会为 Cocoa 框架类(UIAlertView 等)的子类添加前缀,但我不会为自定义 NSObject 子类的实例或类方法添加前缀。
【解决方案3】:

问题 1a 类别

使用前缀,或者避免整个混乱并使用函数。

问题 1b 子类方法

如果一个方法做了足够通用的事情以至于超类也可以实现它,我只需选择一个比 Apple 通常选择的方法名称更“罗嗦”——例如在方法名称中指定一个非标准类型名.当然,这只是减少碰撞的可能性。

如果您需要更高级别的安全性,您可以在执行时对其进行测试(这样您就知道它们何时被引入)并希望每个用户都保持最新状态——或者您可以更加依赖 C 和/或 C++ (他们没有这个问题)。

问题 2

但更新 iPhone 的 iOS 版本时是否也可能发生这种情况?

是的。这不是那么不寻常。当框架更新时(例如通过软件更新),它们可能包含更新的框架。此代码被加载到 objc 运行时中,您始终可以获取已安装框架的 objc 实现的版本。

这也是 OS X 上更广泛的问题,您可以很容易地动态加载代码和/或插件。

【讨论】:

    【解决方案4】:

    一个优雅的解决方案是检查方法是否已经存在,如果不存在则仅添加它:Conditional categories in Mountain Lion

    【讨论】:

    • 谢谢!您链接的问题是我担心的意外覆盖的好例子。但我认为 class_addMethod 并不能解决未来的意外覆盖,但它是有用的信息。
    • 这既不是一种优雅的方法,也不是一种实用的方法来解决覆盖未来方法的问题。
    • @js_ 为什么不呢?解决问题的不是 class_addMethod 本身 - 它实际上是对已经存在的方法的检查。
    • @NikolaiRuhe 为什么不是?然后建议一个更好的而不是讽刺(显然你没有提供有用的答案,甚至没有任何答案......)
    • @H2CO3 此提案仅抑制预期名称冲突。问题是关于方法的意外覆盖。您的代码有几个缺点,例如可能的参数类型不兼容,以及运行时的丑陋骇客。但主要问题是它不会像命名空间那样修复名称冲突。您的方法可能只是做一些不同于(未来)框架方法的事情。
    猜你喜欢
    • 1970-01-01
    • 2012-03-08
    • 2014-03-21
    • 1970-01-01
    • 1970-01-01
    • 2013-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多