为什么NSString响应appendString?

use*_*769 15 objective-c nsstring

我正在使用MacOS-X 10.6.7和Xcode 4.0.2上的Objective-C中的respondsToSelector方法来识别对象是否会响应某些消息.根据手册,NSString不应该响应appendString:而NSMutableString应该.这是测试它的代码片段:

int main (int argc, const char * argv[])
{

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSString *myString = [[NSString alloc] init];

    if ([myString respondsToSelector:@selector(appendString:)]) {
        NSLog(@"myString responds to appendString:");
    } else {
        NSLog(@"myString doesn't respond to appendString:");
    }

    // do stuff with myString

    [myString release];
    [pool drain];
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

Class02[10241:903] myString responds to appendString:
Run Code Online (Sandbox Code Playgroud)

我有点期待相反的事情.NSString对象如何响应appendString:这里发生了什么,我失踪了?

小智 10

简短回答:该字符串是类型NSCFString,是一个继承自的类NSMutableString,因此它响应声明的方法的选择器NSMutableString,包括超类.

答案不是那么简短:基础字符串是使用Core Foundation字符串免费桥接的.开发人员使用opaque类型CFStringRef(桥接NSString)和CFMutableStringRef(桥接NSMutableString)来引用这些字符串,因此,乍一看,有两种不同类型的字符串:immutable和mutable.

从Core Foundation内部实现的角度来看,有一个名为的私有类型struct __CFString.此私有类型保留一个位字段,除其他信息外,还存储字符串是可变的还是不可变的.具有单一类型简化了实现,因为许多函数由不可变和可变字符串共享.

每当调用对可变字符串进行操作的Core Foundation函数时,它首先读取该字段并检查该字符串是可变的还是不可变的.如果参数应该是一个可变的字符串,但事实上它不是,则该函数返回错误(例如_CFStringErrNotMutable)或失败一个断言(例如__CFAssertIsStringAndMutable(cf)).

无论如何,这些都是实施细节,它们将来可能会发生变化.这一事实NSString没有声明-appendString:并不意味着每一个NSString实例不来相应的选择响应-想可替代性.同样的情况适用于其他可变/不可变类,如NSArrayNSMutableArray.从开发人员的角度来看,重要的是返回的对象是与返回类型匹配的类型 - 它可以是类型本身或该类型的任何子类型.类集群使这更复杂,但情况本身并不局限于类集群.

总之,您只能期望一个方法返回一个对象,该对象的类型属于返回值类型的层次结构(即类型本身或子类型).不幸的是,这意味着您无法检查Foundation对象是否可变.但话说回来,你真的需要这张支票吗?


您可以使用该CFShowStr()函数从字符串中获取信息.在您的问题的示例中,添加

CFShowStr((CFStringRef)myString);
Run Code Online (Sandbox Code Playgroud)

您应该得到类似于的输出:

Length 0
IsEightBit 1
HasLengthByte 0
HasNullByte 1
InlineContents 0
Allocator SystemDefault
Mutable 0
Contents 0x0
Run Code Online (Sandbox Code Playgroud)

哪里

Mutable 0
Run Code Online (Sandbox Code Playgroud)

意味着字符串实际上是不可变的.


Eik*_*iko 1

您不应该假设某个方法存在。该方法可能会在内部使用或出于任何原因而存在。从技术上讲,它只是私有 API。

您只有公开声明(文档)的合同,并且它们不显示该消息。因此,如果您使用其他功能,请做好很快陷入麻烦的准备。