freedom is all

Programming

Properties and Memory Management in Objective-C

Posted in iOS, iPhone, Objective-C, Programming on April 13th, 2011 by brandon – 2 Comments

I tweeted earlier about dot notation in Objective-C. Twitter is not a good place to explain some things so I figured it is a great excuse to get back into blogging. So here goes.

Dot notation is fine. I’m not necessarily against it in most programming languages. However, it does not have a place in Objective-C. I’m not necessarily against it, but I think it is confusing. Especially for people new to the language.

In the days before dot notation, accessors and mutators (getters and setters) had to be written (or generated by a tool) and usually had the same structure. This boilerplate code was tedious to write, but it was absolutely necessary to know how to write the different kinds accessors and mutators. Some of the mutators would simply assign an ivar, others would release the old version and retain the new version. Some would release the old version and copy the new version. They would trigger Key Value Observing updates, trigger other operations to occur and many other things. Knowing when to use one or the other was usually the first step in being proficient in Objective-C.

Fast forward to the modern Objective-C runtime. This version introduces a new concept to the language called a property. These defined properties, via an @property keyword, would give a clue to the compiler of what kind of property it needs to be. The different options are: nonatomic, atomic, retain, assign, copy, readonly, readwrite, getter= and setter=. Each of these types gives the compiler the directions on what kind of accessor and mutator to generate when @synthesize is used in the implementation file (you have to provide your own implementations if @dynamic is used). This saves a ton of time! I love Objective-C properties because I don’t have to write boilerplate code. However, this does not excuse anyone from knowing how to supply their own mutator for whatever reason.

Now to the part of the modern runtime that I don’t like:  Dot notation. Dot notation is simply syntactic sugar when dealing with Objective-C objects. I didn’t fully understand that until I wrote something like this:

- (void) setFoo:(id) newFoo {
    self.foo = newFoo;
}

When I ran the application and set my property, I was greeted with a rather large stack trace that looked a lot like recursion. I was confused because I knew I was setting the property like it should be. What I didn’t realize is the code was getting executed as:

- (void) setFoo:(id) newFoo {
    [self setFoo:newFoo];
}

Wow! After that day, I stopped using dot notation. This was when I was learning Cocoa and very new to Objective-C. Now, I’m pretty proficient in both and am spending my day job working with Cocoa Touch and Objective-C. Today I saw the following type of code in a project I’m working on and I was taken back to my early days in Objective-C:

self.myProperty = [[Foo alloc] init];

See the problem there? We can assume that myProperty is defined as being nonatomic and retain (assign brings in other issues that I’ll talk about later). The problem with the above code is the fact that the newly created object is leaking immediately. The equivalent code without using dot notation is:

[self setMyProperty:[[Foo alloc] init]];

The leak is easier to see there. The Foo object is allocated with a retain count of 1 and then the setMyProperty: selector is called which increments the retain count again. No balancing release (or autorelease) is sent to the new object. The most common ways to handle this situation are as follows:

Foo *newFoo = [[Foo alloc] init];
[self setMyProperty:newFoo];
[newFoo release];
[self setMyProperty:[[[Foo alloc] init] autorelease];
self.myProperty = [[[Foo alloc] init] autorelease];

Personally, I prefer the top option. To me, it is clearer as to what is going on and there is no confusion. The second and third options are pretty much identical with the third being the less desirable in my opinion.

Why not use

self.myProperty = [[Foo alloc] init];

and configure myProperty to be assign? Well, it breaks convention. As Aaron Hillegass would say, “A stylish programmer wouldn’t do it like that.” The reason it breaks convention is because you have to balance the alloc with a release somewhere. The best place would be in the dealloc method and it would be there with other ivars that were “assigned” that don’t require a balancing release. A great example is a delegate.

Delegates are usually assigned because we don’t want to create retain cycles. Since we’d be picking and choosing which assign properties to release, we’re making our code harder and harder to understand. Especially for someone new to the codebase.

Noel Llopis said something about chaining assignments with Objective-C on twitter. For those that aren’t familiar with this, you can do this type of thing in C:


This assigns 42 to the variables i, j, and k. One might think that they could write:
But they would find out quickly that this won’t work. If we look at what happens behind the scenes, the above line gets turned into:

See the problem? Mutators have a return type of void, so nothing is getting assigned to obj1. In fact, the compiler will complain about that.

Update: Must have been an older version of LLVM that had that bug.  I can’t recreate the above scenario so it is retracted.

The final point I’ll make about dot notation is about C structs. In order to access a part of a C struct, you use dot notation. When you do this, you are accessing the value directly. This means that there are now two contexts to think about when using dot notation. You have to ask yourself, “Am I using a struct or an Objective-C object?” I’m a fan of consistency, so since I have the option of avoiding dots in my Objective-C code; I will avoid them.

Ultimately, your coding style is yours and I’m not going to tell you how to write your code. I will say that you need to understand what each line of code you write does. If you are using dot syntax in your Objective-C, I won’t unfollow you on twitter or anything like that. I will, however, expect that you understand what is going on in your code.

I’m a fan of clarity of intent being the most important thing in code that I write. I’m not writing this code for me to consume, I’m writing it so others will be able to read it. Will you see some dot notation in my code? Yes, usually when I’m being lazy or prototyping though. For the most part I will use the bracketed message syntax.