views:

65

answers:

2

Getting up to speed with Cocoa iPhone/Mac development, I know the difference between atomic and nonatomic properties, and the performance difference with nonatomic, but every definition of IBOutlet properties I've seen specifies nonatomic, over the default atomic. I've not been able to find an explanation of whether this is a requirement or just advantageous? Can anybody explain further?

Thanks!

-Ben

+1  A: 

It's not a requirement. In fact you can get away with not declaring properties at all.

@interface MyClass
{
    IBOutlet UIView *someView;
}

@end

However, people use properties because of easier memory management (the retain keyword will ensure the outlet stays in memory until release is called; it would be released when the view was unloaded otherwise I believe). The nonatomic just follows along because it is set to atomic by default -- if there is no reason to use atomic you should use nonatomic.

vakio
A: 

Most UIKit classes/functions are not thread-safe (UIGraphics was recently made somewhat thread-safe, apparently, but I suspect UIView still isn't), so it makes little sense to use atomic properties. An atomic "retain" property solely prevents this kind of race condition (assuming pointer assignments are already atomic):

  • Thread A does NSLog([obj.property description]);
  • Thread B does obj.property = nil; causing the property to be released. If this happens at some point between A getting the property and printing it with NSLog, it might crash (the "description" string could be owned by the object and might go away when it's released, for example).

In general, you need a lot more than atomic getters/setters for most kinds of thread synchronization; the setter gains a @synchronized block and the getter (assuming a "retain" property) gains a @synchronized block, a retain, and an autorelease. A @synchronized block consists of _lock and _unlock method calls (IIRC). That's four method calls and an exception handler!

Making properties atomic for "thread-safety" or "robustness" is a bit like making variables volatile "for robustness" instead of using memory barriers — it might appear to be safer, but it usually just adds extra overhead for no benefit and might hide underlying concurrency issues.

EDIT: And yes, the autorelease has to be in the getter, not the setter. Otherwise the object is owned by B's autorelease pool, which might get released at any time, but will tend to hide the bug since the object will stick around for longer before getting released.

tc.