3

I've been up and down the Google and the Stack and read many articles if not outright debates over ivars and properties. But still, even after all this reading I remain confused.

I understand ivar's are private and properties are typically used to expose (well) class properties. But I understand properties to be more than that, they contain Getters and Setters and when it comes to memory management (even under ARC) I can see the benefit to using them exclusively.

But my question is; does any of this matter anymore now that we have ARC? (see comment in example code below).

Consider:

@interface MyClass
@property(strong) NSMutableArray *myArray;
@end

@interface MyClass

-(instancetype)init {

    if (self = [super init]) {

        self.myArray = [NSMutableArray array];

        // OR

        // Will this NOT call the Setter?  Hence, leading
        // to possible memory leak issues?
        _myArray = [NSMutableArray array];

    }

    return self;
}
@end
  • Basic difference: properties have automatic getters and setters, ivars do not. – SevenBits Jan 20 '15 at 00:51
  • yes, ARC works at the property level--release/retain are called when a strong location (not just property) is assigned to. – nielsbot Jan 20 '15 at 01:00
  • `_myArray = value` will not call the setter, but it will retain the assigned value. – nielsbot Jan 20 '15 at 01:00
  • will retain the value, but will not release the previous (because the setter wasn't called) -- am I getting that right? –  Jan 20 '15 at 01:02
  • yes, the previously stored value will be sent a *release* message. When you assign a value to a strong variable, the value currently in the variable is released. – nielsbot Jan 20 '15 at 01:03
  • That does not, however, necessarily happen if the property is declared to be `weak`. – SevenBits Jan 20 '15 at 01:05
  • @nielsbot I know, I am just clarifying for anyone who is reading who might not know. – SevenBits Jan 20 '15 at 01:07
  • Also, whether the object is actually sent a *release* message could be considered an implementation detail. Just think of it as a strong reference to the object being deleted (somehow). – nielsbot Jan 20 '15 at 01:08

4 Answers4

1

self.myArray = [NSMutableArray array]; is considered bad form in init. You should avoid the use of setters entirely in your initialisation. The risk is that a subclass may override the method, in which case you're calling a method on a class that hasn't been inited yet (because it's got only as far as initing you). See the obligatory Mike Ash citation.

_myArray = ... does not call the setter and is therefore the correct form for an init regardless of whether you also have a property.

ARC makes correct memory-management all but a none issue. The debate is exclusively what you want technically to expose and how adaptable you want your internal code to be. I tend to prefer explicit instance variables because that shouts 'private implementation detail'.

Tommy
  • 99,986
  • 12
  • 185
  • 204
1

Back in the old days of Objective-C, you had ivars, and if you wanted to let some other class set or read them then you had to define a getter and a setter.

As I explained to you, with properties you get the setter and getter for free (almost!) along with an instance variable. So when you define a property, you can set the atomicity as well as assign/retain/copy memory management semantics.

Most people leave the ivar name the same as the property name, but it can be made to be something else when you write your @synthesize statement (i.e., @synthesize foo=_foo; means make an ivar named _foo for the property foo).

Note that as of Xcode 4.6, you do not need to use the @synthesize statement - by default will the compiler prepend the ivar's name with _. So @synthesize is no longer recommended by Apple for new code.

SevenBits
  • 2,836
  • 1
  • 20
  • 33
0

That first call will call the setter while the second will not, however both calls will overwrite the ivar _myArray. For example, if you did self.myArray = @[@"Hello"]; and then _myArray = @[@"World"], printing out both self.myArray or _myArray will print @[@"World"].

If you instead write your own method -(void)setMyArray;, It could possibly do different things, but then you also won't get the private ivar _myArray without declaring it yourself.

Krys Jurgowski
  • 2,871
  • 17
  • 25
  • Ok, so this confirms to my understanding. Typically when I code and I see to SET a value, I use property and when I read a value I use the ivar variable. –  Jan 20 '15 at 01:01
  • 1
    It's recommended to use the property methods for both setting and getting unless you have a good reason not to. One of the reasons for this is if you ever want to use KVO to observe changes or simply do anything extra while setting or getting a variable, you can easily add that functionality later. Of course, inside the setter and getter, you'll want to use the ivar so you don't run into an infinite loop. – Krys Jurgowski Jan 20 '15 at 01:06
0

In both cases the assigned value will be retained, since you are assigning it to a strong variable. (Strong is the default for variables that reference object instances)

In the first example the method -setMyArray: will be called, which in the case of a generated setter will store the value to _myArray. In the second case, -setMyArray: will not be called.

For the given code the object already assigned to _myArray will have its reference count properly decremented when the _myArray is set again. (The existing strong reference to the object will be deleted.)

nielsbot
  • 15,922
  • 4
  • 48
  • 73