当你使用
str = @"abcd"
这种方式时,编译器无法识别该代码模式是否返回一个新分配的对象,因此不会触发有关将新对象直接赋值给
__weak
变量的警告。
此外,像
@"abcd"
这样的字符串字面量存储在程序的可执行文件中,它永远不会被释放。
retain
和
release
操作实际上不会改变其保留计数。它的保留计数设置为一个神奇数字,表示一个不朽的对象。因此,您的
__weak
变量
str
实际上没有被设置为nil,因为它所引用的对象没有被释放。这就是为什么它打印出
abcd
的原因。
事实上,如果您分配一个字符串字面量(而不是其他类型的字面量,比如数组字面量
@[a, b, c]
),clang特意抑制警告。请参阅
clang源代码中的注释:
static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc,
Expr *RHS, bool isProperty)
如果我们把类型更改为NSArray
并使用数组字面量,我们会收到一个警告:
![array literal assignment warning](https://istack.dev59.com/B4pOk.webp)
接下来...当您说str = [[NSString alloc] init]
时,您会收到警告,因为编译器认识到[[NSString alloc] init]
是通常返回新对象的代码模式。
然而,在特定的情况下[[NSString alloc] init]
,你会发现str
仍然没有被设置为nil。这是因为-[NSString init]
被特殊处理为返回全局空字符串对象。它实际上不会在每次调用时创建一个新对象。
__weak NSString *str;
str = [[NSString alloc] init];
NSLog(@"%ld %p [%@]", CFGetRetainCount((__bridge CFTypeRef)str), str, str);
输出:
2018-01-24 01:00:22.963109-0600 test[3668:166594] 1152921504606846975 0x7fffe55b19c0 []
1152921504606846975是一个特殊的保留计数,表示该对象是不可释放的。