Iphone NSArray和NSMutableArray的Objective-c内部构件
对于所有进入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
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
'scopy
方法实际上返回[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