[英]Assigning object to weak reference in Objective-C?
According to ARC
in iOS
, an object must have at least one strong
reference to stay in memory, when there is no strong
reference ( ie. reference count becomes 0 ), the object will be deallocated from memory and we will have no longer access to the object.根据iOS
中的ARC
,一个对象必须至少有一个strong
引用才能留在内存中,当没有strong
引用时(即引用计数变为 0 ),该对象将从内存中释放,我们将无法再访问物体。
But I am getting strange behavior in my code.但是我的代码中出现了奇怪的行为。
I am assigning to weak
reference NSString
in code, when I write [[NSString alloc] init];
当我编写[[NSString alloc] init];
时,我在代码中分配给weak
引用NSString
[[NSString alloc] init];
Xcode give warning . Xcode 发出警告。
__weak NSString *str;
str = [[NSString alloc] init];
Assigning retained object to weak property;将保留对象分配给弱属性; object will be released after assignment.对象将在分配后释放。
if I do like this, Xcode doesn't gives any warning,如果我这样做,Xcode 不会发出任何警告,
__weak NSString *str;
str = @"abcd";
NSLog(@"%@", str);
Output : abcd输出:abcd
My Question is:我的问题是:
Why it is printing "abcd"
as output.为什么将"abcd"
打印为输出。 even if str
is a weak reference variable.即使str
是弱引用变量。 Who is keeping this NSString
object which value is "abcd"
in memory?谁在内存中保留这个值为"abcd"
NSString
对象?
When you say str = @"abcd"
, you're not using a code pattern that the compiler recognizes as returning a newly-allocated object, so you don't trigger the warning about a direct assignment of a new object to a __weak
variable.当您说str = @"abcd"
,您没有使用编译器识别为返回新分配对象的代码模式,因此您不会触发有关将新对象直接分配给__weak
变量的警告.
Furthermore, a string literal like @"abcd"
is stored in your program's executable file.此外,像@"abcd"
这样的字符串文本存储在程序的可执行文件中。 It's never deallocated.它永远不会被解除分配。 The retain
and release
operations don't actually change its retain count. retain
和release
操作实际上并没有改变它的保留计数。 Its retain count is set to a magic number indicating an immortal object.它的保留计数被设置为一个表示不朽对象的幻数。 So your __weak
variable str
doesn't actually get set to nil, because the object it references doesn't get deallocated.所以你的__weak
变量str
实际上并没有被设置为 nil,因为它引用的对象没有被释放。 That's why it prints abcd
.这就是它打印abcd
的原因。
In fact, clang specifically suppresses a warning if you assign a string literal (as opposed to some other kind of literal like an array literal @[a, b, c]
).事实上,如果您分配字符串文字(而不是其他类型的文字,如数组文字@[a, b, c]
),clang 会特别抑制警告。 See the comment in the clang source code :查看clang 源代码中的注释:
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;
}
So if we change the type to NSArray
and use an array literal, we get a warning:因此,如果我们将类型更改为NSArray
并使用数组文字,我们会收到警告:
Moving on… You get the warning when you say str = [[NSString alloc] init]
because the compiler recognizes that [[NSString alloc] init]
is a code pattern that typically returns a new object.继续……当您说str = [[NSString alloc] init]
时会收到警告,因为编译器识别出[[NSString alloc] init]
是通常返回新对象的代码模式。
However , in the particular case of [[NSString alloc] init]
, you'll discover that str
again doesn't get set to nil.但是,在[[NSString alloc] init]
的特殊情况下,您会发现str
再次没有设置为 nil。 That's because -[NSString init]
is special-cased to return a global empty-string object.那是因为-[NSString init]
是特殊情况,用于返回全局空字符串对象。 It doesn't actually make a new object on each call.它实际上并没有在每次调用时创建一个新对象。
__weak NSString *str;
str = [[NSString alloc] init];
NSLog(@"%ld %p [%@]", CFGetRetainCount((__bridge CFTypeRef)str), str, str);
Output:输出:
2018-01-24 01:00:22.963109-0600 test[3668:166594] 1152921504606846975 0x7fffe55b19c0 []
That 1152921504606846975 is the magic retain count indicating an immortal object. 1152921504606846975 是表示不朽对象的魔法保留计数。
#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);
After debug with your code I found that [str class]
is NSCFConstantString
and it's retainCount is 1152921504606846975
.在调试您的代码后,我发现[str class]
是NSCFConstantString
并且它的 retainCount 是1152921504606846975
。
for the retainCount in Objective-C
, If the object's retainCount equals 1152921504606846975
, it means "unlimited retainCount", this object can not be released though it is assigning to weak reference.对于Objective-C
的retainCount,如果对象的retainCount等于1152921504606846975
,则表示“无限制的retainCount”,这个对象虽然赋值给弱引用,但不能释放。
All __NSCFConstantString
object's retainCount is 1152921504606846975
, which means __NSCFConstantString
will not be released whether it is __weak .所有__NSCFConstantString
对象的 retainCount 都是1152921504606846975
,这意味着__NSCFConstantString
不会被释放,无论是__weak 。 The NSString
created using the *str = @"abcd";
使用*str = @"abcd";
创建的NSString
will be the same object if they are same value whether how many times to be written.将是相同的对象,如果它们是相同的值,无论要写入多少次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.