Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rough draft of iOS style guidelines #16

Closed
croaky opened this issue Sep 11, 2012 · 1 comment
Closed

Rough draft of iOS style guidelines #16

croaky opened this issue Sep 11, 2012 · 1 comment
Assignees

Comments

@croaky
Copy link
Contributor

croaky commented Sep 11, 2012

Shamelessly ripped from LevelUp. Passing off to Mark for his edits.

  • In general, all compiler warnings in Objective-C should be treated as errors and corrected. Warnings of form

    'SomeClass' may not respond to '-someSelector'

    always indicate a scope issue, and even though these selectors may be resolved at runtime in certain cases, you should always resolve these warnings by importing the appropriate files and, in rare cases, by typecasting your objects explicitly when selector naming conflicts arise.

  • Use @class to forward declare classes in class interfaces and #import to load the actual headers in the corresponding class implementation. For example, do the following in ClassA.h:

    @class ClassB;
    @interface ClassA {
      ClassB * classBInstance;
    }
    

    and the following in ClassA.m:

    #import "ClassB.h"
    
  • When defining an inheritance or protocol conformance relationship, be as specific as possible with #import statements in the class interface:

    #import "Three20/TTView.h" // Recommended; specific
    #import "Three20/Three20.h" // Not recommended; unnecessary
    @interface MyView : TTView { ... }

  • Strictly type objects whenever possible. Loosely type objects only when necessary. id is a special type in Objective-C, and the compiler will not generate warnings for any messages passed to an object of type id.

  • Where available, use class initializers rather than autoreleased instance initializers:

    NSArray* array1 = [NSArray array];                       // Already autoreleased
    NSArray* array2 = [[[NSArray alloc] init] autorelease];  // init then autorelease; unnecessary
    
  • For transient instances, use autorelease rather than init followed by release:

    NSArray* array1 = [NSArray array];          // autoreleased (array1 retain count: effectively 0)
    instance1.collection = array1;              // retained (array1 retain count: 1)
    NSArray* array2 = [[NSArray alloc] init];   // retained (array2 retain count: 1)
    instance2.collection = array2;              // retained (array2 retain count: 2)
    [array2 release];                           // released (array2 retain count: 1)
    
  • Always use YES and NO as BOOL values:

    BOOL boolValueA = YES;          // Recommended
    BOOL boolValueB = false;        // Inadvisable
    
  • Do not explicitly compare BOOL values to YES or NO in boolean logic expressions:

    BOOL boolValue = NO;
    ...
    if (boolValue) { ... }            // Acceptable for BOOL types
    if (boolValue == YES) { ... }     // Unnecessary
    
  • Explicitly compare pointer types to nil in boolean logic expressions:

    SomeClass* someInstanceA = nil;
    SomeClass* someInstanceB = nil;
    ...
    if (someInstanceA != nil) { ... }  // Recommended
    if (someInstanceB) { ... }         // Ambiguous; BOOL or pointer type?
    
  • Avoid using the app delegate -- the class that conforms to the UIApplicationDelegate protocol -- as an all-purpose utility singleton. Only instance variables and methods that relate directly to the flow of the application should be contained within the app delegate.

Style

  • Always follow the Coding Guidelines for Cocoa as well as the Google Objective-C Style Guide.

  • Join pointers to their type followed by a single space: NSString* someString;

  • Sort @class statements alphabetically:

    @class CLLocationManager;
    @class TTURLRequestModel;
    @class ZClass;
    
  • Group #import statements by "framework", sorting them alphabetically within each group. Actual Apple frameworks should be first:

    #import <Foundation/Foundation.h>  // Apple
    #import <objc/message.h>           // Apple
    #import <objc/runtime.h>           // Apple
    #import <UIKit/UIKit.h>            // Apple
    #import "Three20/Three20.h"        // Three20
    #import "AClass.h"                 // Application
    #import "ZClass.h"                 // Application
    
  • Group method prototypes by static and instance methods, sorting them alphabetically by selector within each group:

    + (void)staticMethodWithClassA:(A*)a classB:(B*)b;
    + (void)staticMethodWithClassA:(A*)a classC:(C*)c;
    - (NSString*)instanceMethodWithClassA:(A*)a classB:(B*)b;
    - (NSString*)instanceMethodWithClassA:(A*)a classC:(C*)c;
    
  • Only list method prototypes in a class interface if it is specific to that class. Do not list inherited method, conformed protocol (formal or informal) method prototypes, synthesized @property methods, etc.:

    - (id)initWithString:(NSString*)string label:(UILabel*)label;    // Appropriate; class-specific
    - (id)init;                                                      // Not appropriate; inherited from NSObject
    - (void)setValue:(id)value forUndefinedKey:(NSString*)key;       // Not appropriate; conforms to NSObject (NSKeyValueCoding)
    
  • Use #pragma mark to group method implementations in the following order, sorting methods alphabetically by selector within each group:

    1. Inline class category methods from the inline class category interface.

    2. Class extension methods from the class extension interface. Add "(Private)" to the #pragma mark label for these methods and "(Public)" to the #pragma mark label for class methods.

    3. Class methods from the class interface.

    4. Subclass methods from the subclass interface and in the order in which the class inherits from subclasses in the inheritance hierarchy.

    5. Formal protocol methods from the protocol documentation and in the order in which the protocols are adopted in the class interface.

    6. Informal protocol methods from the informal protocol documentation and in alphabetical order by the categorized class name first and by the informal protocol name second.

      For example, assuming ClassC inherits from ClassB -- which inherits from ClassA, which inherits from NSObject -- conforms to the ProtocolD and ProtocolE formal protocols, conforms to the NSObject (NSKeyValueCoding) and NSObject (UINibLoadingAdditions) informal protocol, and has both a named class category and a class extension, ClassC.m would be look like the following:

      #pragma mark -
      #pragma mark ClassC (InlineClassCategory) Methods
      ...
      #pragma mark -
      #pragma mark ClassC Methods (Private)
      ...
      #pragma mark -
      #pragma mark ClassC Methods (Public)
      ...
      #pragma mark -
      #pragma mark ClassB Methods
      ...
      #pragma mark -
      #pragma mark ClassA Methods
      ...
      #pragma mark-
      #pragma mark NSObject Methods
      ...
      #pragma mark -
      #pragma mark ProtocolD Methods
      ...
      #pragma mark -
      #pragma mark ProtocolE Methods
      ...
      #pragma mark -
      #pragma mark NSObject (NSKeyValueCoding) Methods
      ...
      #pragma mark -
      #pragma mark NSObject (UINibLoadingAdditions) Methods
      ...
      
  • Although Apple suggests that the word "Additions" be appended to a framework class name when creating a category on that class, this naming convention is very likely to result in naming conflicts when using multiple third-party frameworks/libraries. Instead, name framework class categories as follows: NSString+XYZAdditions.h, where XYZ is the chosen private API prefix or NSString+DescriptiveNameAdditions.h, where DescriptiveName somehow describes what the addition does.

  • In the dealloc method, release all non-weakly-associated instance variables and set all instance variables to nil:

    [instanceVariableA release];  // Strong association
    [instanceVariableB release];  // Strong association
    instanceVariableA = nil;      // Strong association
    instanceVariableB = nil;      // Strong association
    instanceVariableC = nil;      // Weak association
    
@ghost ghost assigned hyperspacemark Sep 11, 2012
@jferris
Copy link
Contributor

jferris commented Nov 9, 2012

We have some iOS stuff in master now. Is this already resolved?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants