如何避免在 Objective-C 运行时缓存 NSString 实例?

How I can avoid caching of NSString instances in Objective-C runtime?

Objective-C 可以缓存短字符串。如果您 运行 修改了 的代码,您将得到结果,该字符串相同(一个实例)(为 OS X Yosemite 构建)。如何避免这种行为?

NSString* value1;
NSString* value2;
__weak NSString* weakValue1;
__weak NSString* weakValue2;
NSMutableString* resultText = [NSMutableString new];

@autoreleasepool
{
    value1 = [[NSString alloc] initWithFormat:@"Heo: %d", 1];
    value2 = [[NSString alloc] initWithFormat:@"Heo: %d", 1];
    if (value2 == value1)
    {
        NSLog(@"same strings");
    }
    [self injectToString:value2];
    weakValue1 = value1;
    weakValue2 = value2;

    [resultText appendFormat: @"  value1 = %@", weakValue1];
    [resultText appendFormat: @"  value2 = %@", weakValue2];

    value1 = nil;
    value2 = nil;
}
[resultText appendFormat: @"  value1 = %@", weakValue1];
[resultText appendFormat: @"  value2 = %@", weakValue2];

NSLog( @"resultText = %@", resultText );

UPD

问题:

  1. (value2 == value1) = true,但是如果将@"Heo: %d" 更改为@"Hellow: %d",它将return false。

  2. weakValue1 和 weakValue2 do not 变成 nil(从不),但是如果你改变 @"Heo: %d" 到@"Hello: %d",然后 weakValue1 和 weakValue2 变成 nil。我觉得是问题。

你说的是避免实施细节,所以无论你想出什么 可能 都会过时,但我能想到有两件事不太可能改变。

首先,您可以全力以赴并重新构建字符串:

@interface NSString (WSSUncached)

+ (instancetype)WSSUncachedStringWithString:(NSString *)s;

@end

@implementation NSString (WSSUncached)

+ (instancetype)WSSUncachedStringWithString:(NSString *)s
{
    NSMutableString * newS = [NSMutableString string];

    [s enumerateSubstringsInRange:(NSRange){0, [s length]}
                          options:NSStringEnumerationByComposedCharacterSequences
                       usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                           [newS appendString:substring];
                       }];

    return newS; // or [NSString stringWithString:newS]; if you're feeling especially crazy
}

@end

这不会在 10.9 SDK 上引发。

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

    @autoreleasepool {

        NSString * s = @"Hello, world!";
        NSCAssert([NSString WSSUncachedStringWithString:s] !=
                    [NSString WSSUncachedStringWithString:s],
                  @"No good: even constructed strings are cached.");

    }
    return 0;
}

这方面的变化是可能的,当然:具有 ASCII 值的 C 数组,或者首先传输到 NSData...

更明智的选择可能是从文件中加载字符串。

NSString * fileString = [NSString stringWithContentsOfFile:@"Helloworld.txt"
                                                  encoding:NSUTF8StringEncoding
                                                     error:NULL];
NSString * sameFileString = [NSString stringWithContentsOfFile:@"Helloworld.txt"
                                                      encoding:NSUTF8StringEncoding
                                                         error:NULL];
NSCAssert(fileString != sameFileString, @"Nope; file strings are cached too.");

即使 Helloworld.txt 为空,这个断言也会成功。