84

Just want to make sure that I got it right:

  1. Do I need to __unsafe_unretain objects that I don't own?
  2. If an object is __unsafe_unretained Do I need to use assign in the @property? Does that mean that the object is not retained, and just refers to the object I assign to?
  3. When would I want to use it except of delegates?
  4. Is that an ARC thing or was it in use before?
Luke
  • 11,426
  • 43
  • 60
  • 69
shannoga
  • 19,649
  • 20
  • 104
  • 169

4 Answers4

194

The LLVM Compiler 3.0 introduces four new ownership qualifiers: __strong, __autoreleasing, __unsafe_unretained, and __weak. The first three are available even outside ARC, as per the specification.

As Joshua indicates, by default all pointers are implied to be __strong under ARC. This means that when an object is assigned to that pointer, it is retained for as long as that pointer refers to it. This is fine for most things, but it opens up the possibility for retain cycles, as I describe in my answer here. For example, if you have an object that contains another object as an instance variable, but that second object has a strong link back to the first one as its delegate, the two objects will never be released.

It is for this reason that the __unsafe_unretained and __weak qualifiers exist. Their most common use is for delegates, where you'd define a property for that delegate with the weak or unsafe_unretained attribute (assign is effectively unsafe_unretained), and then match that by marking the respective instance variable with __weak or __unsafe_unretained. This means that the delegate instance variable will still point back at the first object, but it will not cause that object to be retained, thus breaking the retain cycle and allowing both objects to be released.

Beyond delegates, this is useful to break any other retain cycles that might form in your code. Helpfully, the Leaks instrument now includes a Cycles view, which shows retain cycles it discovers in your application in a graphical manner.

Both __unsafe_unretained and __weak prevent the retention of objects, but in slightly different ways. For __weak, the pointer to an object will convert to nil on the deallocation of the object it points to, which is very safe behavior. As its name implies, __unsafe_unretained will continue pointing to the memory where an object was, even after it was deallocated. This can lead to crashes due to accessing that deallocated object.

Why would you ever use __unsafe_unretained then? Unfortunately, __weak is only supported for iOS 5.0 and Lion as deployment targets. If you want to target back to iOS 4.0 and Snow Leopard, you have to use the __unsafe_unretained qualifier, or use something like Mike Ash's MAZeroingWeakRef.

Community
  • 1
  • 1
Brad Larson
  • 170,088
  • 45
  • 397
  • 571
  • 2
    And of course `__unsafe_unretained` can be useful for defining C arrays of `NSString` constants and the like, e.g. `NSString __unsafe_unretained *myStrings = { @"Foo", @"Bar", @"Baz", nil };` – jlehr Dec 21 '11 at 17:45
  • Thanks for the great answer. when I use __unsafe_unretained will iOS refer to it as _weak if the device OS is 5? or it is set at compile time on xCode? – shannoga Dec 21 '11 at 18:51
  • 2
    @shannoga - No, you have to manually specify `__weak` as a qualifier for it to use those kind of pointers. You can still use `__unsafe_unretained` with a purely 5.0 target and it won't behave like `__weak`. If you want something that will switch between the two modes depending on whether your target supports it, you could use a compiler-specific define like I suggest here: http://stackoverflow.com/a/8594878/19679 – Brad Larson Dec 21 '11 at 18:58
  • 4
    @jlehr - `NSString *myStrings = { @"Foo", @"Bar" };` is not valid Objective-C syntax; `@"Foo"` has type `NSString*` by itself. Perhaps you meant `NSString *myStrings[] = { @"Foo", @"Bar" };`, but in that case I don't really understand how `__unsafe_unretained` would be especially useful. – Quuxplusone Jul 11 '12 at 02:40
  • 2
    @Quuxplusone Right on both counts -- I was mixing up C arrays with structs. What I should have said is that `__unsafe_unretained` can be useful C structs members that point to NSString constants, e.g. `struct foo { __unsafe_unretained NSString * const s; int x; };` – jlehr Jul 11 '12 at 11:53
  • @BradLarson also, I have found replacing the '__unsafe_unretained' in __unsafe_unretained __block void (^assignPropertyValues)(NSDictionary*, NSManagedObject*); with '__weak' as i am calling that the block from within the block leads to a warning: Assigning block literal to a weak variable; object will be released after assignment – Rambatino Dec 02 '14 at 14:10
  • 1
    Also has implications for `Class`. See: http://stackoverflow.com/a/14245894/392847 – Quintin Willison May 04 '17 at 13:42
4
  1. No, you could also use weak for objects that you do not own.
  2. No, you could also use unsafe_unretained on the property.
  3. My understanding is that unsafe_unretained items are just like weak, without the additional safety of clearing them out when the item they point to gets released (and the overhead that goes with it).
  4. This is entirely an ARC thing.
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Actually, oddly enough, `unsafe_unretained` iVars, when set at runtime, behave just like `strong` ones, which leads me to believe that `unsafe_unretained` is simply a compiler hint, while weak is not. More information here: http://stackoverflow.com/questions/11621028/discovering-at-runtime-which-of-a-class-instance-variables-are-declared-weak#comment15389310_11621028 – Richard J. Ross III Jul 23 '12 at 22:45
4

__unsafe_unretained is identical to what the default storage of an object was prior to ARC. With ARC the default is now __strong meaning you have a reference to it until your reference goes out of scope.

Quuxplusone
  • 23,928
  • 8
  • 94
  • 159
Joshua Weinberg
  • 28,598
  • 2
  • 97
  • 90
1

Another observation on __unsafe_unretained: I've got crashes in my app on the device and NOT on simulator with iVars declared as __unsafe_unretained! Yes, it was a bug in the code from ARC migration, but it was the first time I noticed such a difference between device and simulator.

Gerd
  • 328
  • 1
  • 2
  • 9