Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

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?

like image 489
Roshni Kumari Avatar asked Jan 24 '18 06:01

Roshni Kumari


People also ask

What is a weak reference Objective C?

Pointers that are not retained are often referred to as “weak” in Objective-C documentation that predates the garbage collector. These are references that are allowed to persist beyond the lifetime of the object. Unfortunately, there is no automatic way of telling whether they are still valid.

What is strong reference and weak reference in Objective C?

A reference to an object is any object pointer or property that lets you reach the object. There are two types of object reference: Strong references, which keep an object “alive” in memory. Weak references, which have no effect on the lifetime of a referenced object.


1 Answers

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.

like image 185
rob mayoff Avatar answered Oct 25 '22 16:10

rob mayoff