The Code Commandments: Best Practices for Objective-C Coding (updated for ARC)

Updated April 26, 2012 for ARC

Preface

I don’t normally post highly technical stuff to my blog, but here’s an exception that I hope will benefit the Mac and iOS (iPhone & iPad) developer community. So if you’re not part of that, feel free to skip it.

Introduction

This article is a cumulative list of the most commonly-violated best practices for Objective-C coders that I’ve witnessed in my many years of experience with the language. I call them “commandments” because there are many good reasons to observe them and few, if any valid reasons not to. However, when I show these practices to other developers, they frequently raise one big objection…

The Big Objection: Won’t That Hurt Performance?

This is almost never a legitimate objection. If you can show me any case where code written in conformance to any of the following policies has become the performance bottleneck, you have my blessing to optimize that code with an exception to the policy, as long as how you’re breaking the policy and why are clearly documented in the code.

Why?

These policies target code safety, clean memory management, understandability, and maintainability. Most of them are not performance enhancers. Nonetheless, writing code with performance in mind is never the way to go first. Always write clean, correct code and then optimize only when and where profiling indicates you need it. In a typical UI-driven application, the single biggest bottleneck is almost always the user, followed by network access, and then disk access. Nonetheless, premature optimization is rampant among programmers who are concerned that if they don’t use every optimization trick they’ve been taught, their application will be dog slow. This simply isn’t true.

Important General Advice

Even if you understand how your code operates when you write it, that doesn’t mean others will understand it so completely before they attempt to modify it, and it doesn’t mean that you will understand it yourself when you revisit it months later. ALWAYS strive to make your code self-documenting by using verbose symbol names and add detailed comments in sections of code where meaning is not obvious despite clear and descriptive symbols. Any time you need to work around a bug or misfeature in an API you are using, isolate your workaround to a single method, explain your workaround and put a keyword like KLUDGE in your comments so you can easily find and fix these trouble spots later.

Things This Article Doesn’t Cover (Yet)

  • Key Value Coding (KVC) and Key Value Observing (KVO). You should use them.

Added April 26, 2012

Thou Shalt…

ALWAYS use Automatic Reference Counting (ARC). This article has been revised to remove references to pre-ARC code style. All new code should be written using ARC, and all legacy code should be updated to use ARC (or kept in a very tight box with a pretty API covering it up.)


Thou Shalt…

ALWAYS use the @private directive before any instance variable declarations, and NEVER access instance variables directly from outside the class.

Why?

  • Preserves information hiding (encapsulation)
  • Limits to methods in the class implementation cases where instance variables are accessed directly.
  • The default privacy for instance variables is @protected, which means subclasses can access these instance variables freely. But there has to be a very good reason to allow subclasses to do this— everything that a superclass exposes to the outside world becomes part of its contract, and the ability to change the internal representation of a class’s data without changing its API or contract is an important benefit of object-oriented encapsulation. By keeping your instance variables private, you make it clear that they are implementation details and not part of your class’s API.

Bad

  1. @interface Foo : NSObject {
  2.         int a;
  3.         NSObject* b;
  4.         // …
  5. }
  6. // method & property declarations…
  7. @end

Better

  1. @interface Foo : NSObject {
  2.         @private
  3.         int a;
  4.         NSObject* b;
  5.         // …
  6. }
  7. // method & property declarations…
  8. @end

Thou Shalt…

ALWAYS create a @property for every data member and use “self.name” to access it throughout your class implementation. NEVER access your own instance variables directly.

Why?

  • Properties enforce access restrictions (such as readonly)
  • Properties enforce memory management policy (strong, weak)
  • Properties provide the opportunity to transparently implement custom setters and getters.
  • Properties with custom setters or getters can be used to enforce a thread-safety strategy.
  • Having a single way to access instance variables increases code readability.

Bad

  1. @interface Foo : NSObject {
  2.         @private
  3.         NSObject* myObj;
  4. }
  5. @end
  6.  
  7. @implementation Foo
  8. - (void)bar {
  9.         myObj = nil;
  10. }
  11. @end

Better

  1. @interface Foo : NSObject {
  2.         @private
  3.         NSObject* myObj;
  4. }
  5.  
  6. @property(strong, nonatomic) NSObject* myObj;
  7.  
  8. @end
  9.  
  10. @implementation Foo
  11. - (void)bar {
  12.         self.myObj = nil;
  13. }
  14. @end

Thou Shalt…

ALWAYS use the “nonatomic” attribute on your properties, unless you are writing a thread-safe class and actually need access to be atomic, and then put a comment in the code that this was your intent.

Why?

Classes with properties that aren’t declared “nonatomic” may give the impression that they were designed with thread-safety in mind, when in fact they weren’t. Only drop the “nonatomic” qualifier from properties when you have actually designed the class for thread-safety.

Bad

  1. @interface Foo : NSObject
  2.  
  3. @property(strong) NSObject* myObj;
  4.  
  5. @end

Better

  1. @interface Foo : NSObject
  2.  
  3. @property(strong, nonatomic) NSObject* myObj;
  4.  
  5. @end

Better

  1. // This class and all it’s properties are thread-safe.
  2. @interface Foo : NSObject
  3.  
  4. @property(strong) NSObject* myObj;
  5.  
  6. @end

Thou Shalt…

NEVER allow your instance variable names to be confused with property names, or with data member names. ALWAYS end your instance variable names with an underscore. UNLESS you are subclassing a 3rd-party class which already has a data member of the same name, in which case pick another non-similar name or add another underscore and put a comment in as to why you did this.

Use “@synthesize name = name_;” in your implementation, instead of just “@synthesize name;”

Why?

  • Even within the class implementation you have to have a very good reason to access a data member directly, instead preferring property accessors.
  • Apple uses “_name” for their private instance variables, and by using “name_” for yours, you avoid naming conflicts.
  • Apple has begun to use the “name_” convention in code examples and templates that demonstrate developer-level code.

Bad

  1. @interface Foo : NSObject
  2.  
  3. @property(strong, nonatomic) NSObject* myObj;
  4.  
  5. @end
  6.  
  7. // …
  8.  
  9. @implementation Foo
  10.  
  11. @synthesize myObj;
  12.  
  13. @end

Better

  1. @interface Foo : NSObject
  2.  
  3. @property(strong, nonatomic) NSObject* myObj;
  4.  
  5. @end
  6.  
  7. // …
  8.  
  9. @implementation Foo
  10.  
  11. @synthesize myObj = myObj_;
  12.  
  13. @end

Thou Shalt…

NEVER redundantly add the data member to the class @interface yourself. Allow the @synthesize directive to implicitly add the data member.

Following this practice will yield many classes that explicitly declare no instance variables in the @interface section. When a class has no instance variables, omit the @private declaration, and even omit the opening and closing braces of the data member section.

Why?

  • Reduces redundancy.
  • Simplifies class headers.
  • Avoids the need for forward class declarations in public headers merely so you can declare members of classes that are only actually used in the implementation.

Bad

  1. @interface Foo : NSObject {
  2.         @private
  3.         NSObject* myObj_;
  4. }
  5.  
  6. @property(strong, nonatomic) NSObject* myObj;
  7.  
  8. @end
  9.  
  10. // …
  11.  
  12. @implementation Foo
  13.  
  14. @synthesize myObj = myObj_;
  15.  
  16. @end

Better

  1. @interface Foo : NSObject
  2.  
  3. @property(strong, nonatomic) NSObject* myObj;
  4.  
  5. @end
  6.  
  7. // …
  8.  
  9. @implementation Foo
  10.  
  11. @synthesize myObj = myObj_;
  12.  
  13. @end

You may still need to declare the underlying name of the variable if you need to access it directly, as when writing custom getters and setters:

Won’t Work

  1. @interface Foo : NSObject
  2.  
  3. @property(strong, nonatomic) NSObject* myObj;
  4.  
  5. @end
  6.  
  7. // …
  8.  
  9. @implementation Foo
  10.  
  11. @synthesize myObj;
  12.  
  13. - (NSObject*)myObj
  14. {
  15.         return self.myObj; // recursive call to this getter!
  16. }
  17.  
  18. - (void)setMyObj:(NSObject*)myObj
  19. {
  20.         self.myObj = myObj; // recursive call to this setter!
  21. }
  22.  
  23. @end

Will Work

  1. @interface Foo : NSObject
  2.  
  3. @property(strong, nonatomic) NSObject* myObj;
  4.  
  5. @end
  6.  
  7. // …
  8.  
  9. @implementation Foo
  10.  
  11. @synthesize myObj = myObj_;
  12.  
  13. - (NSObject*)myObj
  14. {
  15.         return myObj_; // No problem.
  16. }
  17.  
  18. - (void)setMyObj:(NSObject*)myObj
  19. {
  20.         // no problem
  21.         myObj_ = myObj; // do the assignment (ARC handles any necessary retaining and releasing)
  22. }
  23.  
  24. @end

Thou Shalt…

NEVER access a data member through an underscore-suffixed symbol UNLESS you are writing a setter or getter.

Bad

  1. @interface Foo : NSObject
  2.  
  3. @property(strong, nonatomic) Bar* myObj;
  4.  
  5. @end
  6.  
  7. // …
  8.  
  9. @implementation Foo
  10.  
  11. @synthesize myObj = myObj_;
  12.  
  13. - (void)someMethod
  14. {
  15.         myObj_ = [[Bar alloc] init];
  16. }
  17.  
  18. @end

Better

  1. @interface Foo : NSObject
  2.  
  3. @property(strong, nonatomic) Bar* myObj;
  4.  
  5. @end
  6.  
  7. // …
  8.  
  9. @implementation Foo
  10.  
  11. @synthesize myObj = myObj_;
  12.  
  13. - (void)someMethod
  14. {
  15.         self.myObj = [[Bar alloc] init];
  16. }
  17.  
  18. @end

Thou Shalt…

NEVER declare internal (private) methods or properties in the class header files. ALWAYS put all internal method and property declarations into a “class extension” in the implementation file.

Bad

  1. //
  2. // Foo.h
  3. //
  4.  
  5. @interface Foo : NSObject
  6.  
  7. @property(nonatomic) int myPublicProperty;
  8. @property(strong, nonatomic) Bar* myPrivateProperty; // This can be accessed by anyone who includes the header
  9.  
  10. - (int)myPublicMethod;
  11. - (int)myPrivateMethod; // So can this.
  12.  
  13. @end

Better

  1. //
  2. // Foo.h
  3. //
  4.  
  5. @interface Foo : NSObject
  6.  
  7. // Only the public API can be accessed by including the header
  8.  
  9. @property(nonatomic) int myPublicProperty;
  10.  
  11. - (int)myPublicMethod;
  12.  
  13. @end
  1. //
  2. // Foo.m
  3. //
  4.  
  5. @interface Foo () // This is a "class extension" and everything declared in it is private, because it’s in the implementation file
  6.  
  7. @property(strong, nonatomic) Bar* myPrivateProperty;
  8.  
  9. - (int)myPrivateMethod;
  10.  
  11. @end
  12.  
  13. @implementation Foo
  14. // …
  15. @end

Thou Shalt…

NEVER use more than one return-statement in a method, and only then as the last statement of a method that has a non-void value-type.
In methods that have a non-void value-type, declare a variable for the value as the very first statement, and give it a sensible default value. Assign to it in code paths as necessary. Return it in the last statement. NEVER return it prematurely using a return-statement.

Why?

Premature return-statements increase the possibility that some sort of necessary resource deallocation will fail to execute.

Bad

  1. @implementation Foo
  2.  
  3. - (Bar*)barWithInt:(int)n
  4. {
  5.         // Allocate some resource here…
  6.  
  7.         if(n == 0) {
  8.                 // …and you have to deallocate the resource here…
  9.                 return [[Bar alloc] init];
  10.         } else if(n == 1) {
  11.                 // …and here…
  12.                 return self.myBar;
  13.         }
  14.  
  15.         // …and here.
  16.         return nil;
  17. }
  18.  
  19. @end

Better

  1. @implementation Foo
  2.  
  3. - (Bar*)barWithInt:(int)n
  4. {
  5.         Bar* result = nil;
  6.  
  7.         // Allocate some resource here…
  8.  
  9.         if(n == 0) {
  10.                 result = [[Bar alloc] init];
  11.         } else if(n == 1) {
  12.                 result = self.myBar;
  13.         }
  14.  
  15.         // …and deallocate the resource here, you’re done!
  16.  
  17.         return result;
  18. }
  19.  
  20. @end

Thou Shalt…

Understand what autorelease pools are for, when they are created and destroyed for you, and when to create and destroy your own.

  • Automatically by NSRunLoop on each pass
  • Automatically by NSOperation
  • By you, at the start and end of threads
  • By you, whenever you must create and release a large number of objects before you’ll cede control back to the run loop.

Under ARC, you create autorelease pools with the @autoreleasepool { … } construct.


Thou Shalt…

ALWAYS prefer class-level convenience constructors over init-constructors. All of the foundation framework container classes provide these.

Bad

Better


Thou Shalt…

ALWAYS offer class-level convenience constructors in the API of the classes you write.

Why?

Clients of your class can reap the benefits of being able to keep the previous commandment.

Bad

  1. @interface Foo : NSObject
  2.  
  3. - (id)initWithBar:(int)bar baz:(int)baz;
  4.  
  5. @end

Better

  1. @interface Foo : NSObject
  2.  
  3. - (id)initWithBar:(int)bar baz:(int)baz;
  4.  
  5. + (Foo*)fooWithBar:(int)bar baz:(int)baz;
  6.  
  7. @end

Thou Shalt…

ALWAYS understand when object ownership transfers happen. ARC handles a lot of this for you, but you should still be generally knowledgable of what is going on behind the scenes.

Common ways of taking posession of an object:

  • New objects are owned by you when you call +alloc on a class.
  • New objects are owned by you when you call -copy or -mutableCopy on an instance.
  • You become an owner of an existing object when you assign it to a property with the (retain) or (strong) attribute.

Common ways of releasing ownership an object:

  • Assign another object (or nil) to a property with the (strong) attribute.
  • Let an owning local variable go out of scope.
  • Another object holding a reference to the object is destroyed.

Thou Shalt…

ALWAYS understand the memory management policies of your properties and instance variables, particularly when writing custom getters and setters. Make sure your instance variables have the correct storage policies declared on them in order to let ARC do it’s job. The easiest way to do this is simply to use @synthesize and then override the generated setter and/or getter to access the underlying instance variable, which will have the same storage policy as that declared by the property.

  1. @interface bar
  2.  
  3. @property (strong, nonatomic) id foo;
  4.  
  5. @end
  6.  
  7.  
  8. @implementation bar
  9.  
  10. @synthesize foo = foo_;
  11.  
  12. - (id)foo
  13. {
  14.         return foo_;
  15. }
  16.  
  17. - (void)setFoo:(id)foo;
  18. {
  19.         foo_ = foo;  // Retained/released automatically by ARC because of (strong) attribute on @property above
  20.         [self syncToNewFoo];  // The reason for our custom setter
  21. }
  22.  
  23. @end

Thou Shalt…

NEVER have a -dealloc method if your class unless it must release special resources (close files, release memory acquired with malloc(), invalidate timers, etc.) ARC should be allowed to take care of everything else.


Thou Shalt…

ALWAYS write a custom getter for a property where you have a custom setter, and vice versa.

Why?

Getters and setters need to have symmetrical behavior about memory management, thread safety, and any other side effects they create. You should not rely on a synthesized getter or setter having the proper symmetrical behavior to any custom getter or setter you write. Therefore, if you’re going to provide either the getter or setter yourself, you should provide both.


Thou Shalt…

ALWAYS write a custom setter for a property, and assign that property to nil in your -dealloc method, if there’s something you must ALWAYS do when you release an object (such as invalidating a timer).

Bad

  1. @implementation Foo
  2.  
  3. @synthesize myTimer;
  4.  
  5. - (void)dealloc
  6. {
  7.         self.myTimer = nil; // Timer not invalidated, we could get called back if the timer fires after we’re dealloced!
  8. }
  9.  
  10. @end

Better

  1. @implementation Foo
  2.  
  3. @synthesize myTimer = myTimer_;
  4.  
  5. - (NSTimer*)myTimer
  6. {
  7.         return myTimer_;
  8. }
  9.  
  10. - (void)setMyTimer:(NSTimer*)myTimer
  11. {
  12.         [myTimer_ invalidate];
  13.         myTimer_ = myTimer;
  14. }
  15.  
  16. - (void)dealloc
  17. {
  18.         self.myTimer = nil; // Timer guaranteed not to fire after we’re gone! Still necessary under ARC.
  19. }
  20.  
  21. @end

Why?

ARC takes care of releasing your (strong) or (retain) instance variables at -dealloc time, but it does it directly, rather than by calling your custom setters. So if your custom setters have other side effects (like invaliding timers) you must still make sure to invoke them yourself.


Thou Shalt…

When writing constructors, ALWAYS minimize or eliminate the amount of code that executes before [super init] is called.

Why?

In general, the call to the superclass’ constructor may fail, causing it to return nil. If that happens, then any initialization you do before the call to the super constructor is worthless or worse, has to be undone.

Bad

  1. @implementation Foo
  2.  
  3. - (id)initWithBar:(Bar*)bar
  4. {
  5.         [bar someMethod];
  6.         // other pre-initialization here
  7.        
  8.         if(self = [super init]) {
  9.                 // other initialization here
  10.         } else {
  11.         // oops! failed to initialize super class
  12.         // undo anything we did above
  13. }
  14.  
  15.         return self;
  16. }
  17.  
  18. @end

Better

  1. @implementation Foo
  2.  
  3. - (id)init
  4. {
  5.         if(self = [super init]) {
  6.                 // minimal initialization here
  7.         }
  8.  
  9.         return self;
  10. }
  11.  
  12. // Other methods that put a Foo into a usable state
  13.  
  14. @end

Thou Shalt…

When writing a UIViewController and not using a nib file, ALWAYS create and setup your view hierarchy in -loadView, and never in -init. Your implementation of -loadView is the ONLY place you should ever assign to the view attribute.


Thou Shalt…

NEVER call -loadView yourself! The view attribute of a UIViewController loads lazily when it’s accessed. It can also be automatically purged in a low-memory situation, so NEVER assume that a UIViewController’s view is going to live as long as the controller itself.


Thou Shalt…

ALWAYS set up the views you need once, then show, hide, or move them as necessary. NEVER repeatedly destroy and recreate your view hierarchy every time something changes.


Thou Shalt…

NEVER call -drawRect on a UIView yourself. Call -setNeedsDisplay.


Thou Shalt…

ALWAYS avoid long compound operations in your code. Local variables are your friend.

Bad

  1. NSMutableDictionary* listDict = [[NSMutableDictionary alloc] initWithDictionary:[[NSUserDefaults standardUserDefaults] objectForKey:@"foo"]];

Better

  1. NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
  2. NSDictionary* dataModelDict = [defaults objectForKey:@"foo"];
  3. NSMutableDictionary* listDict = [NSMutableDictionary dictionaryWithDictionary:dataModelDict];

Why?

  • Self-documenting
  • Easier to understand
  • Easier to step through in debugger

Thou Shalt…

NEVER use method names like -drawUI when you aren’t really drawing anything. ALWAYS prefer names like -setupUI or -resetUI, especially if there’s the possibility the method can be called more than once.


Thou Shalt…

NEVER repeat yourself. Have a single, authoritative location for each piece of information or functionality, and deploy it throughout the application, even when it means touching others’ code. NEVER program via copy-and-paste.


Updated October 15, 2010

Thou Shalt…

NEVER call -stringWithString UNLESS you:

  • Are converting an NSString to an NSMutableString.
  • Are converting an NSMutableString to an NSString.
  • Need to guarantee that an NSString* you’ve been handed is really immutable
  • Really need a copy of an NSMutableString because you plan to modify them separately.

Why?

NSStrings are immutable. You should never have to copy an NSString unless you want a mutable copy, or guarantee that an NSString pointer you want to save is not already an NSMutableString (and thus might have its value changed by some other code later.) In fact, attempts to copy NSStrings simply bump up the string’s retain count and return the original string.
[/code]


Added April 26, 2012

Thou Shalt...

ALWAYS use the (copy) storage class for properties that receive objects (like NSStrings or NSArrays) that have mutable subclasses.

Why?

The (copy) storage class of properties (as well as the -copy method) always make IMMUTABLE copies of these objects. So you can rely on the immutability of a copy, while you cannot rely on the immutability of the original. This is also a promise to the caller that you will not mutate objects that are passed to you this way that happen to be only incidentally mutable.


Thou Shalt...

When overriding a method in a superclass, ALWAYS call the superclass' implementation, even if you know that super's implementation does nothing, unless you have a very good reason to not call super's implementation, in which case you must document your reason in the comments.

Why?

  • Super's implementation might not ALWAYS do nothing in the future.
  • Other classes may eventually interpose themselves between your class and the superclass, with non-empty implementations.
  • Makes your code more self-documenting in that it is not possible to call a super implementation unless the method is an override.

Bad

  1. @implementation Foo
  2.  
  3. - (void)awakeFromNib
  4. {
  5.         // do my setup
  6. }
  7.  
  8. @end

Better

  1. @implementation Foo
  2.  
  3. - (void)awakeFromNib
  4. {
  5.         [super awakeFromNib];
  6.  
  7.         // do my setup
  8. }
  9.  
  10. @end

Added October 15, 2010

Thou Shalt...

In conditional statements, NEVER treat pointers or numerical values as booleans.

Why?

Booleans have two values: true and false (by convention in Objective-C we use YES and NO.) Pointers, on the other hand, have a value that is an object, or nil. Numerical values have values that are some number, or zero. While zero and nil evaluate to boolean false in a conditional context, this is a form of implicit type coercion that can make the meaning of your code more difficult to understand. So explicitly test for nil when dealing with pointers, 0 when dealing with integers, 0.0 when dealing with floating point values, etc.

Bad

  1. - (void)fooWithBar:(Bar*)bar baz:(BOOL)baz quux:(float)quux
  2. {
  3.         if(bar && baz && quux) {
  4.                 // do something interesting
  5.         }
  6. }

Better

  1. - (void)fooWithBar:(Bar*)bar baz:(BOOL)baz quux:(float)quux
  2. {
  3.         if(bar != nil && baz && quux != 0.0) {
  4.                 // do something interesting
  5.         }
  6. }

Added October 15, 2010

Thou Shalt...

NEVER use conditional statements to check for nil when you don't have to. In particular, understand that in Objective-C, the act of calling any method on a nil object reference is a no-op that returns zero (or NO, or nil), and write your code accordingly.

Bad

  1. - (void)setObj:(NSObject*)obj
  2. {
  3.         if(obj_ != nil) {
  4.                 [obj_ doCleanup];
  5.         }
  6.         if(obj != nil) {
  7.                 [obj doSetup];
  8.         }
  9.         obj_ = obj;
  10. }

Better

  1. - (void)setObj:(NSObject*)obj
  2. {
  3.         [obj_ doCleanup]; // Does nothing if obj_ == nil
  4.         [obj doSetup]; // Does nothing if obj == nil
  5.         obj_ = obj;
  6. }

Comments? Send a tweet to @ironwolf or use the response form.
I can't respond to everything, but I do read everything!

50 thoughts on “The Code Commandments: Best Practices for Objective-C Coding (updated for ARC)

  1. Great post! I will certainly refer to it from my blog. I started Objective-C1 year ago and while I was already applying most of your recommendations I discovered some new one.

  2. Great post, would have like to have found this one sooner. I have a question about two commandments that seem to contradict eachother, at least it seems that way to me.

    First in \NEVER allow your instance variable names to be confused with property names, or with data member names\ you state that you must always declare data members, and use the underscore after the data member name.
    Then however, in \NEVER redundantly add the data member to the class @interface yourself. Allow the @synthesize directive to implicitly add the data member\, you state that you should never add the data member, and in the example you state the \better\ example of of the former commandment as \Bad\.

    Could you elaborate on this?
    Cheers,
    EP.

  3. Eric-Paul,

    It is always preferable to let @synthesize add the data member for you. In fact, I almost never have the need to add data members directly to the @interface declaration any more. However, the first point is for people who still want or need to add data members, and aren’t ready to make the leap to just letting @synthesize do it for them.

  4. nice idea, but needs some improvement:

    - init… methods do not claim ownership (see memory management rules about naming conventions re: alloc, new, copy) – you’re suggesting otherwise

    - “NEVER release something you didn’t init!” now that’s just confusing and wrong per se. Just remove that statement please.

    - UIViewController docs for -loadView explicitly say that you should *not* call super (in UITableViewController subclasses, on the other hand, you must)

    - people need to be very careful with -retainCount, I’ve seen too many instances of that method being abused… would be good to add a disclaimer that it’s of limited use, and totally unsuitable for fixing memory management errors

    Cheers,
    Anatol

  5. Anatol,

    - init… methods do not claim ownership (see memory management rules about naming conventions re: alloc, new, copy) – you’re suggesting otherwise

    If you do an alloc/init, you have claimed ownership of the resulting object. If you the further call autorelease on that object, you are saying that you’re giving control up at some future point. Please be more specific about your criticism.

    - “NEVER release something you didn’t init!” now that’s just confusing and wrong per se. Just remove that statement please.

    To receive a pointer to an object, then subsequently call -release on it, is incorrect, but unfortunately a practice I have seen many novice Objective-C programmers try. The safer patterns I advocate almost never involve calling -release anywhere.

    - UIViewController docs for -loadView explicitly say that you should *not* call super

    They don’t say that: they only state what the default behavior of the superclass is. In general, it’s find to call [super loadView] as long as you understand the behavior of the superclass, and in general, I advocate calling super’s implementation unless there are specific reasons why you should not. The case I’m covering is where there is no nib file to load, hence the super class will not set the view property.

    - people need to be very careful with -retainCount, I’ve seen too many instances of that method being abused… would be good to add a disclaimer that it’s of limited use, and totally unsuitable for fixing memory management errors

    -retainCount is indeed a debugging function, useful for gaining insight into the memory management patterns in your program. It should never be used to determine, for example, how many extra times you need to call -release on an object in order to cause it to deallocate.

  6. > Please be more specific about your criticism.

    I was – but I guess you misunderstood me.
    My point is: alloc and init are separate methods. yes, you use them in pair, but the ownership is signalled by the “alloc” part, and that’s not being communicated in your post.

    > > – “NEVER release something you didn’t init!” now that’s just confusing and wrong per se. Just remove that statement please.
    > To receive a pointer to an object, then subsequently call -release on it, is incorrect, (…)

    same thing as the first point, basically: it’s perfectly fine and reasonable to take ownership of something via means that don’t involve -alloc (which is probably what you mean by “init”) and -release it later. That’s what -retain is for, after all.
    -init does not signify ownership. You’re confusing newbies here.

    > > – UIViewController docs for -loadView explicitly say that you should *not* call super
    > They don’t say that:

    Ummm…
    “Your custom implementation of this method should not call super.”
    That’s straight from Apple’s docs on UIVC -loadView.

  7. Anatol,

    OK, I have clarified the part that your first two criticisms target (I think.) Let me know what you think.

    And you are correct on your third— it does say don’t call super. Not sure how I overlooked that, so I have removed the bit about calling [super loadView]. I think the reason I put it there in the first place is that I was thinking about more deeply nested UIViewController class hierarchies where some of the subclasses do indeed implement -loadView and thus need to have their overrides called by subclasses.

    Thanks for your clarifications!

  8. Really good advices. I was doing only 2 or 3 of those. I shall now do all of them. Thank you.

    Cheers,
    Medhivok

  9. I’m currently reading the “Table View Programming Guide” from apple and I found this about subclassing UITableViewController :

    “The UITableViewController class implements the foregoing behavior by overriding loadView, viewWillAppear:, and other methods inherited from UIViewController. In your subclass of UITableViewController, you may also override these methods to acquire specialized behavior. If you do override these methods, be sure to invoke the superclass implementation of the method, usually as the first method call, to get the default behavior. ”

    Seems like when subclassing UIViewController we should’nt call the super.loadview but we should for UITableViewController.

    I guess the best way is to check with the doc to do the right thing for each subclassing of apple’s classes.

    Cheers
    Medivhok

  10. Another exception to the ‘always use self.’ rule – don’t call property getters in description subclasses of NSManagedObjects – you don’t want your debug NSLog statements to resolve a fault :)
    You should probably avoid using getters in all subclassed description methods just in case your class uses deferred instantiation but it’s _especially_ bad in Core Data managed objects.

  11. Thank you very much for this commandments! I’m a junior iOS developer and this is very helpful for me. Only one question: all of this commandments is actual today?

  12. Alexander,

    Well the version of the article you read yesterday is still good if you’re not yet using ARC. But as I’ve completely switched to using ARC for some time now, the article was badly in need of an update. I have now done this, so I suggest you give it one more read.

  13. Thank you for a well written article. I would say that your “NEVER use more than one return-statement in a method, and only then as the last statement of a method that has a non-void value-type.” should say something like:

    …except for opt-out checks in the beginning of the method. That way, you can avoid very deep blocks in your methods if there are several things you need to check in the beginning. For example, I would consider this nice coding:

    - (void) myMethodWithValue:(NSString*)value
    {
    if (!value)
    return;

    // do some stuff
    }

  14. Concerning:
    “NEVER have a -dealloc method if your class unless it must release special resources (close files, release memory acquired with malloc(), invalidate timers, etc.) ARC should be allowed to take care of everything else.”

    agreed and also… it is recommended to keep cleanup-code that has impact on things outside the application in other places than dealloc. The reason is that your application might get removed from memory in some extremely special situations without any deallocs being called at all (don’t remember if that can happen on iOS or Mac though).

  15. Pingback: 阅读20120428 » 面壁者语

  16. Ricky,

    I find that if I follow my “NEVER use more than one return-statement in a method” commandment, and my blocks nest too deeply, then it’s a sign that I’m trying to do too much in a single method, and it’s time to refactor.

    With regard to cleanup in dealloc— if your whole application is terminated, then the OS automatically closes any open files, releases all memory, etc. So with regard to those sorts of cleanups, you do them in -dealloc incrementally, and let the OS clean them up if it decides to terminate you. But other sorts of cleanup (such as persisting application data) you of course wouldn’t do in -dealloc, as it indeed may never be called, but rather in your app delegate’s -applicationDidEnterBackground method.

  17. Pingback: [iOS]分享最近发现的一些好东西(120311)

  18. Pingback: Objective-C 编码规范 | yangfei.me

  19. A good read and I don’t agree with everything you say, in particular I don’t think there are any rules in programming that are completely absolute.

    However, you should know that as of about Apple LLVM 3.0 and certainly true in Xcode 4.3, instance variables can now be declared in the @implementation (same syntax, in braces directly after @implementation). There is now no need for any implementation details to appear in the @interface.

  20. Jeremy,

    Thanks for the feedback. Of course there are no absolute rules. In fact, I explicitly say that if you find real reasons to break these rules, then do so… but document why you did it.

    And you’re right about the instance variables in @implementation. Thanks for pointing that out and I’ll incorporate that information when I next update the article!

  21. I disagree with your “one return statement” commandment. It only serves to make code harder to read and test. If you follow a branch until a return you _know_ you can stop there, and not have to worry about tracing it throughout the rest of the method.

    Your resource deallocation example could me much better be implemented like the below. This has the added benefit of adhering to the “Don’t Repeat Yourself”: It’s allocated in one place, and cleaned up in one place.

    @implementation Foo
    – (Bar*)barWithInt:(int)n
    {
    // Allocate some resource here…
    @try {
    if(n == 0) {
    return [[Bar alloc]init];
    } else if(n == 1) {
    return self.myBar;
    }
    }
    @finally {
    // …and deallocate the resource here, you’re done!
    }
    return nil;
    }
  22. My comment about “added benefit of DRY” is bogus. I was looking at the “BAD” example when I wrote that. Sorry about that. But using the @finally {} (or whatever it’s called in Objective-C) _is_ a nice way to get multiple return statements without _having_ to do resource cleanup in multiple places.

  23. About “Use “@synthesize name = name_;” in your implementation, instead of just “@synthesize name;” and “Apple uses “_name” for their private instance variables, and by using “name_” for yours, you avoid naming conflicts.”

    As you can see at the WWDC 2012 Session 405 (Modern Objective-C), new default is “@synthesize name = _name” and Xcode do synthesize by default with “_name” convention.

    I’m sorry for my English.

  24. Coding Guidelines for Cocoa: Typographic Conventions
    Avoid the use of the underscore character as a prefix meaning private in method names (using an underscore character as a prefix for an instance variable name is allowed).

    Coding Guidelines for Cocoa
    Usually, you should not access instance variables directly, instead you should use accessor methods (you do access instance variables directly in init and dealloc methods). To help to signal this, prefix instance variable names with an underscore (_).

  25. You don’t explain why it’s a good idea to use convenience constructors instead of init constructors? This seems to me to be a totally arbitrary constraint with no real benefit. In fact, it seems better to me to use init-based constructors as it becomes easier to see where objects are allocated via searching through the code base. Pre-ARC, I would make the same suggestion as you to favour convenience constructors, but nowadays with ARC convenience constructors seem totally unnecessary.

  26. Dingo,

    Convenience constructors are still useful because they allow the class itself to decide on allocation policy, and relieves the client of the class from having to know about it at all— whether the class returns a singleton, an instance from a pool of reusable instances, or uses some other strategy, it really shouldn’t matter to the client whether a new object is alloc/init-ed at that moment of some prior time. ARC makes this idea even easier as the client doesn’t even need to worry about explicitly retaining or releasing an instance it receives.

  27. Pingback: Properties under ARC: Always or public-only? | Q&A System

  28. Pingback: 代码戒律:Objective-C编码最佳实践 | 宅极客

  29. Iron Wolf,

    Forgive me, but I have one more suggestion for a commandment.

    Put each successive argument onto its own line in multiple argument method calls.

    Bad:
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {

    }

    Better:

    - (void)observeValueForKeyPath:(NSString *)keyPath
    ofObject:(id)object
    change:(NSDictionary *)change
    context:(void *)context
    {
    }

    Reason: Readability!

  30. Sometimes it is just appropriate to return from the method early, there’s no reason to enforce a single return. There are many cases where the nested ifs would be less comprehensible than multiple returns.

  31. BBBBBBBBR,

    I would argue that if you feel like you either need early returns or an incomprehensibly-deep set of nested blocks, then your method is probably too complex and should be refactored into two or more methods.

  32. Terrific list!

    Now that properties are implicitly synthesized, I think all of the rules about instance variables can be replaced by two:

    1. NEVER explicitly declare any instance variables at all. Use properties instead.

    2. NEVER declare private properties in the header file; declare them in an extension interface in the implementation file.

    Also, in the interests of readability and error resistance, I suggest two new rules:

    3. NEVER write the body of a conditional or loop-control statement without curly brackets, as in

    if (foo == nil)
    {
    break;
    }

    4. ALWAYS place each curly bracket on its own line, as shown above.

  33. @David

    Note that in ARC, synthesized accessors are superfluous unless you declare atomic or copy. And if you need atomic and want superior performance, use GCD based accessors instead.

    Placing each curly bracket on a new line is a waste of vertical space IMO.

  34. I find that making code structure more visible is a good use of vertical space.

  35. The wording of my number 3 is perhaps confusing. How about

    3. ALWAYS write the body of a conditional or loop-control statement in curly brackets.

  36. I think curly bracket discussions are really out of scope for this article… they’re really about every C-like language, not just Objective-C, and there’s no objective metric to say which one is better under all circumstances. Ultimately that choice comes down to personal preference and/or company or project coding standards.

  37. Thanks for this awesome post. Just program and develop is not a big thing. Writing an appropriate and standard coding is a main part of development.
    Good luck
    Cheers,
    Mayur

  38. You should update this for the new ivar naming standard: underscore prefix, not suffix. (The suffix style was never widely used.)

  39. Pingback: 四天入门IOS开发 | mapleyuan

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>