Ios 为什么KindOfClass和isMemberOfClass在NSString和NSMutableString中工作不好?

Ios 为什么KindOfClass和isMemberOfClass在NSString和NSMutableString中工作不好?,ios,class,nsstring,objective-c-runtime,nsmutablestring,Ios,Class,Nsstring,Objective C Runtime,Nsmutablestring,我知道反对使用它。但考虑到他们的推理,结果与预期相差甚远 这是我的调试输出-结果在代码中没有差异-以下仅为简洁起见: (lldb) po [@"Hello" isKindOfClass:[NSMutableString class]] true => A mutable string? (lldb) po [[@"Hello" mutableCopy] isKindOfClass:[NSMutableString class]] 0x00000001019f3201 => Wh

我知道反对使用它。但考虑到他们的推理,结果与预期相差甚远

这是我的调试输出-结果在代码中没有差异-以下仅为简洁起见:

(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.
有什么启示吗

更新:

苹果自己的观点:

在类表示的对象上使用此方法时要小心 簇由于类簇的性质,您得到的对象 back可能并不总是您所期望的类型。如果你调用一个方法 返回一个类集群,方法返回的确切类型为 你能用这个物体做什么的最佳指示器

为什么不简单地说不要使用集群类使用
isKindOfClass
isMemberOfClass

该解释禁止从以下角度使用:

你可能会修改一些你不应该修改的东西

而不是说:

这些方法不适用于类集群。 (在上面的示例中,我已经展示了-我显然传递了正确的对象,但仍然没有得到预期的结果。)

更新2:

提交给。

这些方法不会像您在评论中声称的那样“误导”。由于
NSString
NSMutableString
是类集群,因此它们可以分别返回任何具体子类的实例,即
NSString
NSMutableString

碰巧,
NSString
集群中的大多数具体子类也是
NSMutableString
的子类。它们不使用实际的类来控制可变性,而是使用标志或类似的东西。所有文件均完全有效,并符合设计合同的规定

所以,这就是为什么
[@“Hello”是类:[NSMutableString类]]
返回true。你问“一个可变字符串?”没有。这个表达式不是一个有效的可变测试。如文件所述,没有有效的可变性测试。这是你误解的核心。您不能试图询问对象的类以确定它是否是可变的。您必须尊重API中指针的静态类型


编辑:这记录在:

使用返回类型,而不是内省 要确定是否可以更改接收到的对象,则 消息必须依赖于返回值的形式类型。如果是 例如,接收类型为不可变的数组对象时,它应该 不要试图改变它。这不是一种可接受的编程实践 根据对象的类成员身份确定对象是否可变 例如:

if ( [anArray isKindOfClass:[NSMutableArray class]] ) {

    // add, remove objects from anArray

}
出于与实现相关的原因,
isKindOfClass:
在 这种情况可能并不准确。但除此之外的原因,你 不应假设对象是否是基于可变的 关于班级成员资格。你的决定应该完全以 出售对象的方法的签名说明了对象的可变性。 如果您不确定对象是可变的还是不可变的,请假定 它是不变的

下面的几个例子可能有助于澄清为什么这条准则是正确的 重要:

  • 从文件中读取属性列表。当基础框架处理列表时,它会注意到不同的子集。 属性列表是相同的,因此它会创建一组对象,并 所有这些子集之间的份额。之后,您将查看创建的 属性列出对象并决定对一个子集进行变异。突然,而且 不知不觉中,您已在多个位置更改了树

  • 您向
    NSView
    询问它的子视图(使用
    subviews
    方法),它返回一个声明为
    NSArray
    但可能是 内部的
    NSMutableArray
    。然后将该数组传递给其他数组 代码,通过内省确定它是可变的,并且 改变它。通过更改此数组,代码将改变内部数据
    NSView
    类的结构

所以不要基于什么假设对象的可变性 内省告诉你一个物体。将对象视为可变的或不可变的 不是基于API边界上交给您的内容(即 在返回类型上)。如果需要明确地将对象标记为 当您将其传递给客户机时,将其传递给 与对象一起作为标志的信息


正如其他人所提到的,
-isMemberOfClass:
测试是否是该类的实例,而不是任何子类。对于类集群,这将始终返回false,因为公共类是抽象的,永远不会有实例

其他奇怪的结果可能是因为您使用了
po
(print object的缩写)作为非对象值。对布尔表达式使用
p
命令。

这些方法不会像您在注释中所说的那样“误导”。由于
NSString
NSMutableString
是类集群,因此它们可以分别返回任何具体子类的实例,即
NSString
NSMutableString

碰巧,
NSString
集群中的大多数具体子类也是
NSMutableString
的子类。它们不使用实际的类来控制可变性,而是使用标志或类似的东西。所有文件均完全有效,并符合设计合同的规定

所以,这就是为什么
[@“Hello”是类:[NSMutableString类]]
返回true。你问“一个可变字符串?”没有。这个表达式不是一个有效的可变测试。如文件所述,没有有效的可变性测试。这是该计划的核心