如何避免在 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
问题:
(value2 == value1) = true,但是如果将@"Heo: %d" 更改为@"Hellow: %d",它将return false。
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 为空,这个断言也会成功。
Objective-C 可以缓存短字符串。如果您 运行 修改了
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
问题:
(value2 == value1) = true,但是如果将@"Heo: %d" 更改为@"Hellow: %d",它将return false。
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 为空,这个断言也会成功。