
Objective-C Memory Management For Lazy People - jawngee
http://interfacelab.com/objective-c-memory-management-for-lazy-people/
======
vasi
I think the article vastly overstates its case. Nobody disputes that it's
possible to have more-or-less working memory management in ref-counted
Objective-C. But it's clearly harder than in a GC language, else it wouldn't
need seven pages worth of "simple rules" to explain.

Moreover, the author glosses over many of subtleties of reference-counting.
For example, accessors in Java are dead-simple, practically boilerplate. But
in Cocoa, what looks like a perfectly reasonable implementation to a newcomer
is in fact buggy:

    
    
      - setFoo: (id)aFoo {
        [foo release];
        foo = [aFoo retain];
      }
    

Look closely, and you'll realize that if foo and aFoo are in fact the same
object, it will be freed, and foo will have an invalid pointer assigned to it.
Pretty much every Cocoa programmer knows about this, but we shouldn't ahve to.

One of the better Cocoa blogs is written by Mike Ash, and he has quite a few
posts that illustrate some of these issues. For example, the first half of
[http://www.mikeash.com/pyblog/friday-
qa-2010-12-03-accessors...](http://www.mikeash.com/pyblog/friday-
qa-2010-12-03-accessors-memory-management-and-thread-safety.html) talks about
whether or not accessors should autorelease their return values, with pros and
cons for each option. Later on, the money quote: "If you're using garbage
collection, this whole question becomes vastly simpler."

Our author here says that "Cyclic object graphs in Objective-C are not a
problem. At all." But another post by Mike Ash illustrates that it can be
harder to deal with: [http://www.mikeash.com/pyblog/friday-
qa-2010-04-30-dealing-w...](http://www.mikeash.com/pyblog/friday-
qa-2010-04-30-dealing-with-retain-cycles.html) . A great example:

    
    
      _myInstanceVar = [[SomeClass alloc] initWithBlock: ^{
        [self doSomething];
      }];
    

Using 'self' within the block captures it in the closure as a reference, and
then the closure itself is referred to by the instance variable of 'self'.
This cycle is hard for the coder to notice, and will leak.

~~~
seanalltogether
Here's another good example of why memory management isn't as simple as this
article makes it out to be

    
    
        -(void) addAccount:(UIBarButtonItem*)button {
            ListController *list = [[ListController alloc] initWithStyle:UITableViewStylePlain];
            UIPopoverController *pop = [[UIPopoverController alloc] initWithContentViewController:list];
            pop.popoverContentSize = CGSizeMake(320, 200);
            [pop presentPopoverFromBarButtonItem:button permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
            [list release];
            [pop release];
        }

Anyone see the problem with this code?

~~~
rbritton
UIPopoverController does not retain itself and will cause a crash shortly
after that release. Both the iOS SDK and the Cocoa SDK are fairly inconsistent
about which presentation classes require retaining and which handle that
themselves -- UIAlertView does not require it, for example.

~~~
seanalltogether
Precisely, and that's the thing I've come to learn about objective-c memory
management. It's fairly easy to learn as the article points out, but in
practice when you have to interface with other developers code, it can be a
confusing mess.

~~~
andolanra
I know this from practice, having come in halfway through a project on iOS
whose code was exquisitely, terrifyingly awful. I was fine on memory
management; it was hunting down previous memory management errors that took up
most of my time. I ended up giving up and reimplementing certain classes
because it was seriously simpler than debugging the existing code.

I think the issue is that trivial examples—for example, the kind you have in a
blog post or comment—will invariably look simple and easy. In a non-trivial
application, "four basic rules" ends up being four more things that can create
bugs.

~~~
vannevar
And this brings up a point overlooked in the article: it isn't about the time
it takes to do things right, it's also about the time it takes to track down
the problem when you inevitably (you ARE human after all) make a mistake. To
me, that's the real value of GC, because memory allocation errors are tedious
and time consuming to debug.

The author is confusing 'habitual' with 'easy', and the two concepts are very
distinct. And even beyond that he undervalues the debug time saved with
automated GC.

------
blub
Well, before knowing about Obj-C memory management in detail I thought it was
ok. Now that I know the rules it looks painful.

If someone were to write such an article about C, then it would have just one
line: if you malloc, then you must free.

If someone were to write such an article about C++, it would be more involved:
delete if you new, delete[] if you new[] and then they'd explain auto_ptr and
shared_ptr. More complicated that C, but still reasonably easy and you can get
automatic memory management.

On the other hand we have Objective-C, where you apparently need at least 11
paragraphs to explain the basics, only to find out that - yes - you still have
to call malloc and free only with other names and slightly different
behaviour?

~~~
pornel
For me "if you malloc, then you must free" is _much_ harder, because you have
to know whether ownership was passed to you, who else might be using object
when you free it, etc.

In Objective-C there's no owner, everyone borrows objects. You increase retain
count (if you want to hold object for longer than lifetime of a function), and
you decrease retain count when done.

And there are few methods to increase (retain, init, copy, new, property
assignent) and few to decrease count (release, autorelease, nil property
assignment).

To me it's that simple.

~~~
schumihan
Reference count based GC? How would you deal with circular reference?

~~~
eru
You don't.

You'd avoid creating circular structures as much as possible. You can get
pretty far that way.

~~~
schumihan
It's very difficult to avoid it when thing goes complicating. A may reference
B, B may reference C, ... and somewhere, X may reference back to A. If this
strategy makes sense for big project, many hackers work with C++ can use it
either, as the performance overhead is very low.

But in the real world, reference-count based GC just has limited usage.

~~~
eru
> But in the real world, reference-count based GC just has limited usage.

And in theory it doesn't fare much better. Proper garbage collection can have
better performance, and does the Right Thing.

------
statictype
This article has some good points for people who are new to Objective-C, but
(much like the comments you complained that people were downvoting) the
snarkiness and condescension tends to distract from it.

Anyway, thanks for posting it. FWIW, I'm one of the comments you linked to as
being unhelpful.

------
alexyoung
The reason most people find Objective-C memory management hard at first is
they don't realise the importance of recognising and following the
conventions.

Once you know the handful of conventions the article covers, knowing when to
retain or release is pretty easy.

------
wzdd
The original article was strange in that it got a whole lot of things wrong,
but was sufficiently technical that you would actually have to have been an
iOS and an Android developer in order to discuss it. This is why the comments
were so content-free on Hacker News.

(Just one example of the things the article got wrong: The Android emulator
actually defers a lot to the host OS and its own implementations to the point
where I have never seen an OpenGL ES app that runs the same way on the
emulator as it does on real hardware; the Android emulator also runs at full
speed: it's just slower because it's doing more.)

------
chime
> @property (retain) NSString *title;

Why is he retaining NSString? Shouldn't that be (copy)?

~~~
msbarnett
Not necessarily. If you want to avoid situations where title points at a
mutable subclass, yes, but if that isn't a concern, there's nothing inherently
incorrect with a simple retain.

~~~
ajg1977
Except that if someone modifies the string they passed you, your 'copy' of the
string will also change.

~~~
naz
That would only occur if it was an NSMutableString, like the GP said.

