我最近从小牛升级到优胜美地,现在我的单元测试失败了。问题归结为字符串内容的弱指针中的拼写错误。请参阅以下示例代码:
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)
第二个value2
也是(null)
,但事实并非如此。请注意value1
和value2
的内容之间的差异。 value2
缺少冒号。我不明白为什么weakValue2
在value2
设置为nil
时不会自零。一旦我将结肠放回到字符串中,我就得到了我期望的结果。在Mavericks中运行此代码时,我没有看到这种行为。
有谁知道为什么会这样?
我注意到在这个question中,多线程的有效点可能导致弱指针在时间上不是自零,但这不是这里发生的事情。首先,我不是多线程的,如果我单步执行代码并查看变量而不是使用NSLog打印变量,我会得到完全相同的结果。
答案 0 :(得分:5)
问题是您使用弱引用会与系统的实现细节发生冲突。
如果仅引用它引用的对象,则弱引用将被取消分配。其中的时间实际上并没有得到保证,只要引用是非NULL,所引用的对象仍然可行。
对单例的弱引用(永不释放的真正单例)永远不会被无效。
NSString,NSNumber,NSDate和一些其他类在某些时候被实现为某些值的单例。或者很多时候,取决于平台。
因此,对这些类之一的实例的弱引用可能会也可能不会被取消,因为实例实际上可能是单例。
请注意,根据定义,标记指针实际上是单例。
要解决?
不要创建对系统原语/值类的弱引用。
答案 1 :(得分:3)
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");
}
我有结果:“相同的字符串”