Iphone NSArray和NSMutableArray的Objective-c内部构件

Iphone NSArray和NSMutableArray的Objective-c内部构件,iphone,objective-c,ios,Iphone,Objective C,Ios,对于所有进入Objective-c内部的人来说,这是一个非常有趣的问题 所以。。。NSObject为and对象和类返回相同的copy实现(如我所料)。但是,NSArray和NSMutableArray不仅返回对象和类的objectAtIndex:的不同实现,而且每个对象都有不同的实现 有人知道为什么下面的代码会产生这样的行为吗?。。。(至少NSArray和NSMutableArray的类实现是相同的:) 日志 2012-11-06 16:35:22.918 otest[71367:303] NS

对于所有进入Objective-c内部的人来说,这是一个非常有趣的问题

所以。。。
NSObject
为and对象和类返回相同的
copy
实现(如我所料)。但是,
NSArray
NSMutableArray
不仅返回对象和类的
objectAtIndex:
的不同实现,而且每个对象都有不同的实现

有人知道为什么下面的代码会产生这样的行为吗?。。。(至少
NSArray
NSMutableArray
的类实现是相同的:)

日志

2012-11-06 16:35:22.918 otest[71367:303] NSObject instance <c0fa7200>
2012-11-06 16:35:23.757 otest[71367:303] NSObject class <c0fa7200>
2012-11-06 16:35:30.348 otest[71367:303] NSArray instance <809a9b00>
2012-11-06 16:35:31.121 otest[71367:303] NSArray class <70bfa700>
2012-11-06 16:35:33.854 otest[71367:303] NSMutableArray instance <f05f9a00>
2012-11-06 16:35:34.824 otest[71367:303] NSMutableArray class <70bfa700>
2012-11-06 16:35:22.918 otest[71367:303]NSObject实例
2012-11-06 16:35:23.757 otest[71367:303]NSObject类
2012-11-06 16:35:30.348 otest[71367:303]NSArray实例
2012-11-06 16:35:31.121奥特斯特[71367:303]NSArray级
2012-11-06 16:35:33.854 otest[71367:303]NSMutableArray实例
2012-11-06 16:35:34.824 otest[71367:303]NSMutableArray类

实现细节,所有这些。因此,这是一个相对完善的推测

首先,无需跳过这些环来打印十六进制值,只需执行以下操作:

NSLog(@"imp: %p", [NSObject instanceMethodForSelector:@selector(...)]);
请注意,对类对象调用
methodForSelector:
,将返回类方法的IMP

现在,我们来谈谈手头的问题

Objective-C与其他流行的OO语言(但不是全部)的一个区别是类对象实际上是元类的实例。这个元类——实际上除了“元类”之外没有其他名称——碰巧响应了
NSObject
协议(或多或少)。事实上,它有点像是NSObject的派生

因此,当您在实例和类的
NSObject
上获得特定选择器的实现时,它们通常是相同的。请注意,这是允许类成为NSDictionary中的键的原因;类可以被复制
NSObject
copy
方法只返回[self-retain]retain是不可操作的,因为它们[几乎总是]以单例的形式静态编译成二进制。嗯,从技术上讲,
copy
调用
copyWithZone:
它确实返回[self-retain](这就是为什么您必须将
copyWithZone:
子类化,即使不推荐使用分区)

现在,正如hotlicks指出的那样,
NS*Array
是一个类集群,其内部实现细节在过去的几个版本中发生了变化。过去,所有实例都被桥接到配置不同的
NSCFArray
。在最近的版本中,您将看到(原文如此)与不可变和可变实例相对应的实例。大多数情况下,发生的事情不止这些,但这是非常典型的

objectAtIndex:
的实例方法在这两个类之间是不同的,这是类集群的典型特征。集群的要点是提供一个基本接口,并根据该基本接口实现一系列方法(这就是为什么头被划分为核心
@interface
和一系列分类
@interface
;基类中的类别完全按照核心API实现的原因)

在集群内部,公开声明的类有一些具体的子类。这些具体的子类针对特定的任务进行了高度优化——在这种情况下,是不可变的还是可变的阵列存储(但可能有更多的非公共子类针对不同的目的进行了优化)--其中子类覆盖公布的API,以提供各种方法的高度优化版本

因此,您在这两个类中看到的是针对可变和不可变情况优化的
objectAtIndex:
的不同实现

现在,为什么类方法是相同的?好问题。让我们试着调用它:

((void(*)(id,SEL,int))[[NSArray class] methodForSelector: @selector(objectAtIndex:)])([NSArray class], @selector(objectAtIndex:), 0);


2012-11-06 09:18:23.842 asdfasdf[17773:303] *** Terminating app due to uncaught
   exception 'NSInvalidArgumentException', reason: '+[NSArray objectAtIndex:]:
   unrecognized selector sent to class 0x7fff7563b1d0'
啊哈!所以,您要求实现一个方法,该方法在被调用时会抛出一个“无法识别此方法”异常。事实上:

NSLog(@"%@", 
 [NSArray class] respondsToSelector:@selector(objectAtIndex:)] ? @"YES" : @"NO");

2012-11-06 09:24:31.698 asdfasdf[17839:303] NO
看起来运行时正在返回一个IMP,该IMP将抛出一个不错的错误,表明您试图通过迂回的方式使用一个选择器来选择目标对象(在本例中为元类实例)没有响应。这就是为什么选择程序的
实例方法的文档中指出,在目标是否实现选择器可能存在一些问题的情况下,您应该使用
响应选择器:
优先


(好吧,这本书比预期的更像是一本书……希望仍然有用!)

NSArray实例实际上是NSCFArray的“桥接”实例(或类似的东西).实际上是一个子类,虽然我不知道帘子后面的接线是如何工作的。是的,我开始看到类似的东西…有趣的是,上面代码中数组对象的类是u NSArrayI和u NSArrayM。我仍然不确定如何解释关于ThoughtCorrect的效果,如果我错了,请纠正我,但我非常确定
NSObject
's
copy
方法实际上返回[self-copyWithZone:nil]
(或者它获取了一个特定的区域来使用)。元类和其他许多元类一样,实现它是
返回[self-retain]
是的——Mike是对的……通过现在没有操作风格的
copyWithZone:
有一个额外的方法调用。修复了。
NSLog(@"%@", 
 [NSArray class] respondsToSelector:@selector(objectAtIndex:)] ? @"YES" : @"NO");

2012-11-06 09:24:31.698 asdfasdf[17839:303] NO