根据ARC
中的iOS
,当没有strong
引用时,对象必须至少有一个strong
引用留在内存中( ie 。引用计数变为0 ),对象将从内存中释放,我们将无法再访问该对象。
但我的代码中出现了奇怪的行为。
我在代码中分配给weak
引用NSString
,
当我写[[NSString alloc] init];
时,Xcode会发出警告。
__weak NSString *str;
str = [[NSString alloc] init];
将保留对象分配给弱属性;对象将在转让后释放。
如果我喜欢这样,Xcode不会发出任何警告,
__weak NSString *str;
str = @"abcd";
NSLog(@"%@",str);
输出: ABCD
我的问题是
为什么它打印“abcd”作为输出。即使str
是一个弱引用变量。谁将此NSString
对象保留在内存中的值为“abcd”?
答案 0 :(得分:5)
当您说str = @"abcd"
时,您没有使用编译器识别为返回新分配的对象的代码模式,因此您不会触发有关将新对象直接分配给a的警告__weak
变量。
此外,像@"abcd"
这样的字符串文字存储在程序的可执行文件中。它永远不会被解除分配。 retain
和release
操作实际上并未更改其保留计数。其保留计数设置为表示不朽对象的幻数。因此,您的__weak
变量str
实际上并未设置为nil,因为它引用的对象不会被取消分配。这就是它打印abcd
。
实际上,如果你指定一个字符串文字(而不是像数组文字@[a, b, c]
那样的其他类文字),clang会特别禁止警告。请参阅the clang source code中的评论:
static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc,
Expr *RHS, bool isProperty) {
// Check if RHS is an Objective-C object literal, which also can get
// immediately zapped in a weak reference. Note that we explicitly
// allow ObjCStringLiterals, since those are designed to never really die.
RHS = RHS->IgnoreParenImpCasts();
// This enum needs to match with the 'select' in
// warn_objc_arc_literal_assign (off-by-1).
Sema::ObjCLiteralKind Kind = S.CheckLiteralKind(RHS);
if (Kind == Sema::LK_String || Kind == Sema::LK_None)
return false;
S.Diag(Loc, diag::warn_arc_literal_assign)
<< (unsigned) Kind
<< (isProperty ? 0 : 1)
<< RHS->getSourceRange();
return true;
}
因此,如果我们将类型更改为NSArray
并使用数组文字,我们会收到警告:
继续......当你说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是表示不朽物体的魔法保留计数。
答案 1 :(得分:0)
#define TLog(_var) ({ NSString *name = @#_var; NSLog(@"%@: %@ -> %p: %@ retainCount:%ld", name, [_var class], _var, _var, CFGetRetainCount((__bridge CFTypeRef)(_var))); })
__weak NSString *str;
str = @"abcd";
NSLog(@"%@",str
);
TLog(str);
使用您的代码进行调试后,我发现[str class]
为NSCFConstantString
,而且它的retainCount为1152921504606846975
。
对于Objective-C
中的retainCount,如果对象的retainCount等于1152921504606846975
,则表示&#34;无限制retainCount&#34;,虽然该对象分配给弱引用但无法释放
所有__NSCFConstantString
对象的retainCount为1152921504606846975
,这意味着__NSCFConstantString
无论是 __ weak 都不会被释放。使用NSString
创建的*str = @"abcd";
将是相同的对象,如果它们是相同的值,无论要写多少次。