我知道Apple has cautioned反对使用它。但鉴于他们的推理,结果远非相关和预期。
这是我的调试输出 - 结果在代码中没有什么不同 - 下面只是为了简洁:
(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.
有启示吗?
更新:
苹果自己的看法:
Be careful when using this method on objects represented by a class cluster. Because of the nature of class clusters, the object you get back may not always be the type you expected. If you call a method that returns a class cluster, the exact type returned by the method is the best indicator of what you can do with that object.
为什么不简单地说不雇用
isKindOfClass
和 isMemberOfClass
与集群类?该解释防止从以下角度使用:
You might end up modifying something that you are not supposed to.
而不是说:
These methods do not work with class clusters. (in the examples, I have shown above - I am clearly passing correct objects and still not getting expected results.)
更新 2:
归档于 Apple Radar .
最佳答案
正如您在评论中声称的那样,这些方法不会“误导”。因为NSString
和 NSMutableString
是类簇,它们可以返回任何具体子类的实例,它是-a NSString
或 NSMutableString
, 分别。
碰巧的是,NSString
中的大多数具体子类cluster 也是 NSMutableString
的子类.他们没有使用实际的类来控制可变性,而是使用标志或类似的东西。所有完全有效并符合设计契约(Contract)。
所以,这就是为什么 [@"Hello" isKindOfClass:[NSMutableString class]]
返回真。你问“可变字符串?”不,该表达式不是对可变性的有效测试。如文件所述,有 没有可变性的有效测试。这是你误解的核心。您不得尝试询问对象的类以确定它是否是可变的。您必须尊重 API 中指针的静态类型。
编辑:这记录在 Concepts in Objective-C Programming: Object Mutability – Receiving Mutable Objects :
Use Return Type, Not Introspection
To determine whether it can change a received object, the receiver of a message must rely on the formal type of the return value. If it receives, for example, an array object typed as immutable, it should not attempt to mutate it. It is not an acceptable programming practice to determine if an object is mutable based on its class membership—for example:
if ( [anArray isKindOfClass:[NSMutableArray class]] ) { // add, remove objects from anArray }
For reasons related to implementation, what
isKindOfClass:
returns in this case may not be accurate. But for reasons other than this, you should not make assumptions about whether an object is mutable based on class membership. Your decision should be guided solely by what the signature of the method vending the object says about its mutability. If you are not sure whether an object is mutable or immutable, assume it’s immutable.A couple of examples might help clarify why this guideline is important:
You read a property list from a file. When the Foundation framework processes the list, it notices that various subsets of the property list are identical, so it creates a set of objects that it shares among all those subsets. Afterward you look at the created property list objects and decide to mutate one subset. Suddenly, and without being aware of it, you’ve changed the tree in multiple places.
You ask
NSView
for its subviews (with thesubviews
method) and it returns an object that is declared to be anNSArray
but which could be anNSMutableArray
internally. Then you pass that array to some other code that, through introspection, determines it to be mutable and changes it. By changing this array, the code is mutating internal data structures of theNSView
class.So don’t make an assumption about object mutability based on what introspection tells you about an object. Treat objects as mutable or not based on what you are handed at the API boundaries (that is, based on the return type). If you need to unambiguously mark an object as mutable or immutable when you pass it to clients, pass that information as a flag along with the object.
正如其他人所提到的,
-isMemberOfClass:
测试是否是该确切类的实例而不是任何子类。对于类集群,这将始终返回 false,因为公共(public)类是抽象的并且永远不会有实例。其他奇怪的结果可能是因为您使用的是
po
(“打印对象”的缩写)用于非对象值。使用 p
bool 表达式的命令。
关于ios - 为什么 isKindOfClass 和 isMemberOfClass 与 NSString 和 NSMutableString 配合不好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34561101/