7

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.

But I am getting strange behavior in my code.

I am assigning to weak reference NSString in code, when I write [[NSString alloc] init]; Xcode give warning .

__weak NSString *str;
str = [[NSString alloc] init];

Assigning retained object to weak property; object will be released after assignment.

Xcode warning screenshot

if I do like this, Xcode doesn't gives any warning,

__weak NSString *str;
str = @"abcd";
NSLog(@"%@", str);

No Warning Screenshot

Output: abcd

Output Screenshot

My Question is:

Why it is printing "abcd" as output. even if str is a weak reference variable. Who is keeping this NSString object which value is "abcd" in memory?

3
  • 1
    Objective-C string literals are treated differently. They are constants kept in memory so none of the normal memory management rules apply to them. Commented Jan 24, 2018 at 7:00
  • Probably a duplicate of stackoverflow.com/questions/10922888/… Commented Jan 24, 2018 at 7:02
  • I don't think it's a duplicate, because it's interesting to understand why there's a warning in one case but not the other. Commented Jan 24, 2018 at 7:19

2 Answers 2

7

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.

Furthermore, a string literal like @"abcd" is stored in your program's executable file. It's never deallocated. The retain and release operations don't actually change its retain count. 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. That's why it prints 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]). See the comment in 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;
}

So if we change the type to NSArray and use an array literal, we get a warning:

array literal assignment warning

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.

However, in the particular case of [[NSString alloc] init], you'll discover that str again doesn't get set to nil. That's because -[NSString init] is special-cased to return a global empty-string object. 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.

Sign up to request clarification or add additional context in comments.

3 Comments

That means in both cases object will never be deallocated ?
Yes, in both cases you are setting str to an immortal object.
@robmayoff this would mean, the @"abcd", which itself is an object, will stay in the memory as long as the scope(a class or a method) in which it is defined in. But it will be nullified as soon as its parent gets out of the picture. Or since the retain count is such a big number, it will never go out and keep eating the memory? Because even if the parent gets out it will only decrease the retain count by 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);

After debug with your code I found that [str class] is NSCFConstantString and it's retainCount is 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.

All __NSCFConstantString object's retainCount is 1152921504606846975, which means __NSCFConstantString will not be released whether it is __weak. The NSString created using the *str = @"abcd"; will be the same object if they are same value whether how many times to be written.

2 Comments

1152921504606846975 doesn't really mean "unlimited". It is an implementation artifact and may change at any time. In general, retainCount is utterly useless.
No worries. In general, one should ignore both the class and the allocation type used for an object that is sourced from the frameworks. Far better to just treat it as a delta'd reference count. I.e. strong is +1 and when the strong goes out of scope or is nil'd it is -1. Let the system do its thing and if you need to debug, use the object graph inspector to determine what is holding a strong reference.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.