gpt4 book ai didi

iphone - NSArray 和 NSMutableArray 的 Objective-c 内部机制

转载 作者:可可西里 更新时间:2023-11-01 03:03:53 26 4
gpt4 key购买 nike

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

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

有谁知道为什么下面的代码会产生这样的行为?...(至少 NSArrayNSMutableArray 的类实现是相同的:))

NSObject *obj = [[[NSObject alloc] init] autorelease];
NSLog(@"NSObject instance %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod(object_getClass(obj), @selector(copy)))]);
NSLog(@"NSObject class %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod([NSObject class], @selector(copy)))]);

NSArray *array = [[[NSArray alloc] init] autorelease];
NSLog(@"NSArray instance %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod(object_getClass(array), @selector(objectAtIndex:)))]);
NSLog(@"NSArray class %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod([NSArray class], @selector(objectAtIndex:)))]);

NSMutableArray *array1 = [[[NSMutableArray alloc] init] autorelease];
NSLog(@"NSMutableArray instance %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod(object_getClass(array1), @selector(objectAtIndex:)))]);
NSLog(@"NSMutableArray class %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod([NSMutableArray class], @selector(objectAtIndex:)))]);

日志

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>

最佳答案

实现细节,全部。因此,这是一个相对见多识广的猜想。

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

NSLog(@"imp: %p", [NSObject instanceMethodForSelector:@selector(...)]);

请注意,在类对象上调用 methodForSelector: 会返回类方法的 IMP。

现在,回到手头的问题。

Objective-C 与其他流行的 OO 语言(但不是全部)的区别在于,Class 对象实际上是 Metaclass 的实例。那个元类——除了“元类”之外没有真正的名称——恰好响应 NSObject 协议(protocol)(或多或少)。事实上,它有点像 NSObject 的派生物。

因此,当您在实例和类的 NSObject 上获得某些选择器的实现时,它们通常是相同的。请注意,这是允许类成为 NSDictionary 中的键的原因;类可以复制。 NSObjectcopy 方法只是 return [self retain]; 并且,当然,retain 在一个类上是空操作,因为它们 [几乎总是] 作为单例静态编译到二进制文件中。好吧,从技术上讲,copy 调用 copyWithZone: 确实 return [self retain];(这就是为什么你必须子类化 copyWithZone: 即使区域已被弃用)。

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

objectAtIndex: 的实例方法在两个类之间是不同的,这是典型的类集群。集群的要点是提供一个原始接口(interface),其中包含一堆根据该原始接口(interface)实现的方法(这就是为什么 header 分为核心 @interface 和一系列分类 @interfaces;基类中的类别完全根据核心 API 实现。

在内部,集群中有公开声明的类的具体子类。这些具体的子类针对特定任务进行了高度优化——在这种情况下是不可变与可变数组存储(但可能有更多非公共(public)子类针对不同目的进行了优化)——其中子类覆盖了广告 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,它会吐出一个很好的错误,表明您尝试——通过迂回方式——使用目标对象(在本例中为元类实例)不响应的选择器至。这就是为什么 instanceMethodForSelector: 的文档声明您应该先使用 respondsToSelector: 以防目标是否实现选择器存在疑问。

(好吧,这变成了比预期更多的书......希望仍然有用!)

关于iphone - NSArray 和 NSMutableArray 的 Objective-c 内部机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13255572/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com