【问题标题】:Conditionally overriding a system method via categories in Objective-C?通过Objective-C中的类别有条件地覆盖系统方法?
【发布时间】:2010-03-18 14:56:57
【问题描述】:

只有当系统中尚未定义方法时,是否有方法提供方法实现(与框架定义的方法具有完全相同的名称)?例如方法 [NSSomeClass someMethod:] 仅存在于 Mac OS X 10.6 中,如果我的应用程序在 10.5 中运行,我将在类别中提供该方法的定义。但是当应用程序在 10.6 中运行时,我希望运行操作系统提供的方法。

背景:我正在创建一个针对 10.5 和 10.6 的应用。问题是我最近意识到 +[NSSortDescriptor sortDescriptorWithKey:ascending:] 方法只存在于 10.6 中,并且我的代码已经被该方法调用乱扔了。我可以为它提供一个默认实现(因为这次我自己实现它并不太难),但我希望每当我的应用程序在 10.6 上运行时调用“本机”。此外,如果我将来遇到类似的问题(使用更难以实现的方法),我可能无法提供单行替换。

这个问题有点类似于Override a method via ObjC Category and call the default implementation?,但不同的是,我只想在系统还没有实现的情况下提供实现。

谢谢。

【问题讨论】:

    标签: objective-c cocoa macos


    【解决方案1】:

    我会将一个类别中的+[NSSortDescriptor sortDescriptorWithKey:ascending:] 编译成一个单独的包。然后在 main 的最开始,检查 NSSortDescriptor 类是否具有 sortDescriptorWithKey:ascending: 方法和 respondsToSelector:。如果未实现(即您在 -[NSBundle loadAndReturnError:] 加载包。

    这样,您将在 10.6 上运行操作系统提供的方法,并在 10.5 上运行您的实现。

    【讨论】:

      【解决方案2】:

      是的,这是可能的。由于您的目标是 10.5+,我假设您使用的是 ObjC2 运行时,这使得它相当简单。

      Objective-C Runtime Reference 包含您需要的所有方法。具体来说,您可以使用 class_getClassMethod 或 class_getInstanceMethod 来查看该方法是否已存在,如果该类尚不存在,则使用 class_addMethod 将您的实现绑定到该选择器。

      【讨论】:

        【解决方案3】:

        或者,您也可以查找并订阅-[NSSortDescriptor initWithKey:ascending:],然后添加适当的发布声明。

        与更改类本身相比,实现起来更麻烦,但脆弱性和出错率要低得多。如果您以前从未这样做过,则尤其如此。您可能会花费更多时间来加快覆盖速度,而不是仅仅进行查找。

        【讨论】:

          【解决方案4】:

          考虑更改 initWithKey:ascending: 方法和在运行时添加新方法之间的折衷 - 只需子类化 NSSortDescriptor 并将所有 NSSortDescriptor 调用替换为 NSMySortDescriptor;

          //NSMySortDescriptor.h
          @interface NSMySortDescriptor : NSSortDescriptor {
          }
          - (id)initWithKey:(NSString *)keyPath ascending:(BOOL)ascending
          @end
          
          //NSMySortDescriptor.m
          
          @implementation NSMySortDescriptor
          - (id)initWithKey:(NSString *)keyPath ascending:(BOOL)ascending{
             // check if super i.e. has initWithKey:ascending: method
             if( [NSSortDescriptor instancesRespondToSelector:@selector(initWithKey:ascending:)] ) {
                [NSSortDescriptor initWithKey:ascending:];
             }
             else{
               // your custom realization for Mac OS X 10.5
               //...
             }
          }
          @end
          

          【讨论】:

          • NSSortDescriptor 永远不会响应+initWithKey:ascending:,因为(按照惯例)类方法不应该在其名称中使用init
          • 哦,是的,我的错误-取自原始问题代码。当然 [[NSSortDescriptor class] respondsToSelector:@selector(sortDescriptorWithKey:ascending:)];或者哦,是的,我的错误 - 从原始问题代码中获取。当然 [NSSortDescriptor instancesRespondToSelector:@selector(initWithKey:ascending:)]; - 谢谢;
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-07-13
          • 1970-01-01
          • 1970-01-01
          • 2012-09-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多