【问题标题】:Adding a category to NSArray向 NSArray 添加类别
【发布时间】:2010-12-30 12:16:43
【问题描述】:

我向 NSArray 添加了一个类别,其中包含一个用于排序的辅助方法。我的单元测试都通过了,但是在模拟器中运行应用程序时它会爆炸。这可能是因为 NSMutableArray / NSCFArray class cluster stuff?

这是错误: 'NSInvalidArgumentException',原因:'*** -[NSCFArray sortBySequenceAsc]:无法识别的选择器发送到实例 0x489c1f0'

无论如何,将类别添加到 NSArray 和 NSMutableArray 的正确方法是什么?

@interface NSArray (Util) 
- (NSArray *)sortBySequenceAsc;
@end 

@implementation NSArray (Util)
- (NSArray *)sortBySequenceAsc {
    //my custom sort code here
}
@end

【问题讨论】:

    标签: iphone objective-c categories


    【解决方案1】:

    在 NSArray 上放置一个排序类别是个坏主意...它应该是不可修改的...这种类型的功能是 NSMutableArray 的权限,除非您计划提取所有元素并返回一个完全不同的 NSArray 实例,这是令人困惑的行为。

    【讨论】:

    • 可以将排序消息添加到数组中——如果它们返回数组,如示例所示。但是命名确实不好。它应该是sortedArrayBySequenceAsc 或类似的。在 tme 上有人问这个问题,这是定义上下文感知排序的一种优雅方式。今天我更喜欢比较器块。
    【解决方案2】:

    确实,这是因为类集群。您在NSArray 上创建了一个类别,但是您在没有您的方法的私有类__NSCFArray 上调用该方法。我找到了一种解决方法:使用现有数组显式创建一个新的NSArray。新数组的类(对象的isa 指针)将指向类别所在的正确类。

    所以,不要这样做:

    NSArray *array = [someObject someMethod];
    // "array" may be a private class with the same methods as "NSArray", but not yours.
    
    [array yourMethod];
    

    这样做:

    NSArray *array = [NSArray arrayWithArray: [someObject someMethod]];
    // "array" is now explicitly a "NSArray"
    
    [array yourMethod];
    

    它有效,但我希望仍然如此。这是相当不可预测的。这就是为什么我在这里使用开源代码创建了自己的数组实现。我省略了我不需要的方法,并添加了我可能需要的新方法(如shuffle)。我现在正在彻底测试它。

    【讨论】:

      【解决方案3】:

      我想插话,即使派对已经很晚了。

      有时我在创建返回 NSArray 的方法时很懒惰。我实际上返回了我在方法中建立的 NSMutableArray。我想,“什么可能出错?”。我使用它作为返回我正在使用的可变实例的不可变版本的模式。

      除了这正是事情出错的一个例子。显然,Apple 也懒惰地从一个声明它是 NSArray 的接口返回一个 NSMutableArray。如果你在 NSArray 上添加一个类别,它不会被添加到 NSMutableArray。因为 NSMutableArray 是 NSArray,但 NSArray 不是 NSMutableArray。

      【讨论】:

      • 从一个声明它是一个 NSArray 的接口返回一个 NSMutableArray 并不是懒惰的,它是正确的。如果需要不可变数组,请使用复制方法。 stackoverflow.com/a/1769017/190135
      【解决方案4】:

      我在NSArray 上使用过很多次类别都没有问题,所以我猜您的问题出在其他地方(因为您的类别看起来是正确的)。

      由于您收到“无法识别的选择器”错误,这意味着运行时不知道您的类别,这意味着它没有链接到您的二进制文件中。我会检查并确保您的类别的 .m 文件包含在适当的目标中,清理并重新构建。

      编辑:例如,this blog post 显示如何为 NSArray 创建一个类别,以创建原始数组的随机副本。

      编辑#2:Apple 关于类别的文档使用扩展NSArray 功能的具体示例,因此我发现很难相信“推荐”方法是将数组包装在辅助对象中。 Citation (search the page for the five "NSArray" references)

      【讨论】:

      • 我尝试添加一个类别一次并遇到与 OP 相同的问题。我在一些 iPhone 开发网站上读到,在这种情况下,Apple 建议创建一个包含 NSArray 的新对象;也许你只是更小心你的代码。 ;)
      • @Chris - 你有支持包装推荐的链接吗?我以前从未听说过,我有兴趣了解更多。 :)
      • 对不起,很久以前了。我只知道它适用于我的应用程序。
      • @Chris 啊哈,这是有道理的。是的,我完全同意。永远不要继承NSArray。那是要求一个受伤的世界。 =)
      • 感谢您的更新。我现在切换到在 SortUtil 类上使用类方法。如果我回去找出另一个问题,我会发布我做错了什么。
      【解决方案5】:

      推荐的方法是创建一个包含NSArray 的新对象。在NSArray 下面有很多苹果没有告诉我们的东西;当您添加新方法时,您无法访问这些内容,从而导致错误。

      基本上,这样做:

      @interface MySortingArray : NSObject {
           NSArray *theArray
      }
      
      - (int)count;
      - (NSArray *)sortBySequenceAsc;
      
      @end
      
      @implementation MySortingArray
      
      - (int)count {
          return [theArray count];
      }
      
      - (NSArray *)sortBySequenceAsc {
         // your code
      }
      
      @end
      

      【讨论】:

      • 好的。我不会直接向 NSArray 添加方法。
      • 在 NSArray 上创建一个类别究竟如何使对象“无法访问”这个“大量垃圾”?
      • 好吧,我承认我确实简化了很多。我的意思是 OP 很难知道 NSCFArray 和 co. 的复杂性,因为 Apple 没有给你任何文档。这真的比它的价值更麻烦。
      • 虽然这种方法可行,但我不认为这是扩展NSArray 功能的正确 方法。有关更多信息,请参阅我的回答。
      • 这种方法的一个问题是您不能将MySortingArray 对象传递给任何需要NSArray 作为参数的方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-08
      • 1970-01-01
      • 2013-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多