我知道Apple警告不要使用它.但鉴于他们的推理,结果远非相关和预期.
这是我的调试输出 - 代码中的结果没有区别 - 下面只是为了简洁:
(lldb) po [@"Hello" isKindOfClass:[NSMutableString class]] true => A mutable string? (lldb) po [[@"Hello" mutableCopy] isKindOfClass:[NSMutableString class]] 0x00000001019f3201 => What's that? (lldb) po [[@"Hello" mutableCopy] isMemberOfClass:[NSMutableString class]] 0x000000010214e400 => What's that? (lldb) po [@"Hello" isMemberOfClass:[NSMutableString class]] false => Once again?
除此之外,我删除了所有字符串文字代码并测试了以下内容:
NSMutableString * m = [[NSMutableString alloc] initWithString:@"Hello"]; bool b = [m isKindOfClass:[NSMutableString class]]; NSLog(@"%d", b); --> 1 Expected. b = [m isKindOfClass:[NSString class]]; NSLog(@"%d", b); --> 1 Expected. b = [m isMemberOfClass:[NSString class]]; NSLog(@"%d", b); --> 0 Expected. b = [m isMemberOfClass:[NSMutableString class]]; NSLog(@"%d", b); --> 0 Not Expected.
有启发吗?
更新:
Apple自己采取的措施:
在类集群表示的对象上使用此方法时要小心.由于类集群的性质,您获得的对象可能并不总是您期望的类型.如果调用返回类集群的方法,则该方法返回的确切类型是您可以对该对象执行的操作的最佳指示.
为什么不简单地说不使用isKindOfClass
和isMemberOfClass
集群类?
该解释阻止了从以下角度使用:
你最终可能会修改一些你不应该做的事情.
而不是陈述:
这些方法不适用于类集群.(在示例中,我已经在上面显示 - 我显然正在传递正确的对象,但仍未获得预期的结果.)
更新2:
提起Apple雷达.
这些方法不会像您在评论中声称的那样"误导".因为NSString
并且NSMutableString
是类集群,所以它们可以返回任何具体子类的实例,分别是-a NSString
或NSMutableString
.
碰巧,NSString
集群中的大多数具体子类也是其子类NSMutableString
.他们不使用实际的类来控制可变性,而是使用标志或类似的东西.一切都完全有效并符合设计合同.
所以,这就是为什么[@"Hello" isKindOfClass:[NSMutableString class]]
返回true.你问"一个可变的字符串?" 不.该表达式不是可变性的有效测试.据记载,没有有效的可变性测试.这是你误解的核心.您不得尝试询问对象的类以确定它是否可变.您必须遵守API中指针的静态类型.
编辑:这在Objective-C编程中的概念中记录:对象可变性 - 接收可变对象:
使用返回类型,而不是自省为了确定它是否可以改变接收的对象,消息的接收者必须依赖于返回值的正式类型.例如,如果它接收到一个类型为immutable的数组对象,它就不应该尝试改变它.根据类的成员身份确定对象是否可变是不可接受的编程习惯 - 例如:
if ( [anArray isKindOfClass:[NSMutableArray class]] ) { // add, remove objects from anArray }出于与实施相关的原因,
isKindOfClass:
在这种情况下返回的内容可能不准确.但是出于其他原因,您不应该根据类成员资格来确定对象是否可变.您的决定应该完全取决于出售该对象的方法的签名对其可变性的描述.如果您不确定对象是可变的还是不可变的,则假设它是不可变的.几个例子可能有助于澄清为什么这个指南很重要:
您从文件中读取属性列表.当Foundation框架处理列表时,它注意到属性列表的各个子集是相同的,因此它创建了一组在所有这些子集中共享的对象.然后,您查看创建的属性列表对象,并决定改变一个子集.突然间,你没有意识到这一点,你已经在多个地方改变了树.
你要求
NSView
它的子视图(使用subviews
方法),它返回一个声明为一个NSArray
但可能是NSMutableArray
内部的对象.然后将该数组传递给其他代码,这些代码通过内省确定它是可变的并更改它.通过更改此数组,代码正在改变类的内部数据结构NSView
.
所以不要根据内省告诉你的关于对象的内容来假设对象的可变性.根据您在API边界处传递的内容(即基于返回类型)将对象视为可变对象.如果在将对象传递给客户端时需要明确地将对象标记为可变或不可变,请将该信息作为标志与对象一起传递.
正如其他人所提到的那样,-isMemberOfClass:
测试是一个确切类的实例,而不是任何子类.对于类集群,它总是返回false,因为公共类是抽象的,永远不会有实例.
其他奇怪的结果可能是因为您正在使用po
("打印对象"的缩写)非对象值.将该p
命令用于布尔表达式.