我最近从Mavericks升级到Yosemite,现在我的单元测试失败了。问题归结为指向字符串内容的弱指针中的拼写错误。请参阅以下示例代码:
NSString* value1;
NSString* value2;
__weak NSString* weakValue1;
__weak NSString* weakValue2;
NSMutableString* resultText = [NSMutableString new];
@autoreleasepool
{
value1 = [NSString stringWithFormat: @"Hello: %d", 1];
value2 = [NSString stringWithFormat: @"Hello %d", 2];
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 );
此代码的输出为:
resultText = value1 = Hello: 1 value2 = Hello 2 value1 = (null) value2 = Hello 2
我本以为:
resultText = value1 = Hello: 1 value2 = Hello 2 value1 = (null) value2 = (null)
第二CCD_ 1也可以是CCD_。请注意value1
和value2
的内容之间的差异。value2
缺少冒号。我不明白为什么当value2
设置为nil
时weakValue2
不自零。一旦我把冒号放回字符串中,我就会得到我期望的结果。在小牛队运行此代码时,我没有看到这种行为。
有人知道为什么会发生这种事吗?
我在这个问题中注意到,多线程的有效点可能会导致弱指针在时间上不自零,但这不是这里发生的情况。首先,我不是多线程的,如果我遍历代码并查看变量,而不是用NSLog打印它们,我会得到完全相同的结果。
问题是您对弱引用的使用与系统的实现细节相冲突。
当且仅当弱引用所引用的对象被解除分配时,该引用才会无效。其中的时间实际上并不能保证,只要引用不是NULL,引用的对象仍然是可行的。
对singleton的弱引用(从未被释放的真正singleton)永远不会无效。
NSString、NSNumber、NSDate和其他一些类有时被实现为某些值的singleton。或者很多时候,取决于平台。
因此,对其中一个类的实例的弱引用可能无效,也可能不无效,因为该实例实际上可能是单例。
请注意,标记的指针实际上是定义的singleton。
要修复吗?
不要创建对系统基元/值类的弱引用
NSString它不是具体的类,它是许多其他类的接口和工厂。
我发现value1是__NSCFString类的实例,但value2是NSTaggedPointerString类的实例。类NSTaggedPointerString不支持retain和release(我尝试向它注入一些块方法)。
如果你打印这个例子的retainCount,你会得到这样的结果:
po [value2 retainCount] //18446744073709551615
如果你从格式中删除符号":",你会得到这样的结果:
resultText = value1 = Hello 1 value2 = Hello 2 value1 = Hello 1 value2 = Hello 2
之所以发生这种情况,是因为上面的字符串是NSTaggedPointerString类的实例。我认为这是非常奇怪的行为。
p.S.
如果您在value2字符串中添加":",您将得到结果:
resultText = value1 = Hello: 1 value2 = Hello: 2 value1 = (null) value2 = (null)
:)
UPD
若字符串的长度小于8,那个么它的字符串将被缓存到内存中。
UPD-2
我已将代码更改为:
value1 = [NSString stringWithFormat: @"Heo: %d", 1];
value2 = [NSString stringWithFormat: @"Heo: %d", 1];
if (value2 == value1)
{
NSLog(@"same strings");
}
我得到的结果是:"相同的字符串"