简体   繁体   English

在Objective-C中将对象分配给弱引用?

[英]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.对象将在分配后释放。

Xcode 警告截图

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. retainrelease操作实际上并没有改变它的保留计数。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM