34

Here is how I used to write a custom retained setter before:

- (void)setMyObject:(MyObject *)anObject
{
   [_myObject release], _myObject =  nil;
   _myObject = [anObject retain];

   // Other stuff
}

How can I achieve this with ARC when the property is set to strong. How can I make sure that the variable has strong pointer?

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
aryaxt
  • 76,198
  • 92
  • 293
  • 442
  • Is this really how you used to write setters? I think you should add an `if` statement checking, if `anObject` is not the same as `_myObject`. If they both reference the same object with retain count 1, you deallocates the object on first line and crash on second. – Tricertops Jan 26 '13 at 22:35
  • Sorry about the crash, you are right, you are nullifying it. You are almost right with that second part, but there is one case: the only place where the object is referenced is this property itself. Very simplified: `self.title = self.title;`, but this may happen in more complex situation. You don't know where the object came from, you assign it to property, and boom it is lost. – Tricertops Jan 26 '13 at 23:52
  • … and not just it is lost, but in this specific case the code will crash. On release, it may get deallocated, you nullify ivar, but then retain deallocated object – crash. – Tricertops Jan 27 '13 at 12:32
  • @iMartin I couldn't get it to crash using your example, but you are right it may cause a crash, so it's best to do the equal check – aryaxt Jan 28 '13 at 01:59
  • @aryaxt, actually, you are not wrong. If the only place an object is referenced is a property and you set another object to that property first object should be deallocated anyway. `self.title = self.title;` won't crash but not because of the setter, it's because of the getter. Getter should always return an autoreleased object, a getter never should assume it will have object longer than receiver needs to. Returning an object in a getter without retaining and autoreleasing it again is a mistake. That's exactly why above code won't crash. – Töre Çağrı Uyar Jun 18 '13 at 11:17

2 Answers2

66

The strong takes care of itself on the ivar level, so you can merely do

- (void)setMyObject:(MyObject *)anObject
{
   _myObject = anObject;
   // other stuff
}

and that's it.

Note: if you're doing this without automatic properties, the ivar would be

MyObject *_myObject;

and then ARC takes cares of the retains and releases for you (thankfully). __strong is the qualifier by default.

Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
  • what does your `@synthesize` look like with (both) of these options? – Alex Gray Jul 09 '12 at 11:51
  • 2
    @alexgray your synthesize generally looks like `@synthesize myObject = _myObject` to keep the names of the iVar and property different. See here (http://stackoverflow.com/questions/822487) for whether that's a good idea. – Dan Rosenstark Jul 09 '12 at 12:36
  • 1
    @alexgray UPDATE with the new stuff (um, LLVM 4.0 or Xcode 4.4 or something) you don't have to write synthesize, IF you were lucky enough to ignore all the know-it-alls on SO and use the underscore as a prefix. – Dan Rosenstark Aug 22 '12 at 03:41
  • 1
    I don't think you need `__strong` because it's inferred if left out. – ma11hew28 Sep 25 '12 at 14:05
  • I may be missing something here, but I'm confused by the ivar you have listed for non-auto properties—wouldn't the ivar for this situation be `MyObject *_myObject;`? – Robert Nall Dec 07 '12 at 01:10
  • @RobertNall you can call the ivar whatever you want, but you're right. I've adjusted the answer. – Dan Rosenstark Dec 08 '12 at 01:44
  • @Yar thanks for the answer. Now what if the `myObject` property was `copy` instead of `strong`? Do you need to `copy` it in the custom setter via `_myObject = [anObject copy];` with ARC? – Alec Feb 06 '13 at 22:34
  • 1
    If you're doing the setter (a custom setter), then you have to do the copy as you suggest. If you don't, then the copy is done automatically for you. Copy implies strong ownership, so if you're doing the ivar, it should be like it is here (with no specification it would be `strong`). See here for more confusion: http://clang.llvm.org/docs/AutomaticReferenceCounting.html and search on "copy implies __strong ownership" – Dan Rosenstark Feb 07 '13 at 00:34
5

Just to sum up the answer

.h file

//If you are doing this without the ivar
@property (nonatomic, strong) MyObject *myObject;

.m file

@synthesize myObject = _myObject;

- (void)setMyObject:(MyObject *)anObject
{
    if (_myObject != anObject)
    {
        _myObject = nil;
        _myObject = anObject;
    }
    // other stuff
}
Adithya
  • 4,545
  • 3
  • 25
  • 28
  • 18
    Checking is unnecessary, you won't get a performance increase or reliability with checking like `_myObject != anObject`, you can only get a little bit performance decrease. Also setting iVar to `nil` is unnecessary, too. Won't get any reliability with `_myObject = nil;`, too. – Töre Çağrı Uyar Jun 18 '13 at 11:25