Coding Conventions and Style

This section documents modern Objective-C as implemented by Apple Clang in the current Xcode release — Objective-C 2.0 plus ARC, literals and subscripting, instancetype, Clang modules, lightweight generics, nullability and @available — as published at Apple Developer Documentation and the Clang Objective-C specifications, which are the references these pages are written and verified against.

This content was generated with the assistance of AI and should be verified against developer.apple.com before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

Objective-C’s conventions carry unusual weight. Because the language has no namespaces, no overloading and no access modifiers on methods, naming is the API design — and because key-value coding, KVO and Swift import all key off method names, breaking a convention breaks behaviour, not just style. Apple’s Coding Guidelines for Cocoa is the normative document; this page summarises what it asks for.

Naming

The Governing Principle

Clarity beats brevity, but not verbosity. An Objective-C method name should read as a phrase at the call site and should not require a comment to explain what it does.

// Clear
[document saveToURL:url ofType:type completionHandler:handler];
[array removeObjectAtIndex:2];

// Too terse -- what does "t" mean? what does "at" index?
[document saveTo:url type:t handler:h];
[array rmObjAt:2];

// Needlessly long -- "Object" adds nothing here
[array removeTheObjectLocatedAtTheGivenIndex:2];

Never abbreviate unless the abbreviation is already universal in Cocoa: max, min, info, temp, alt, rect, URL, ID, HTTP. Write setBackgroundColor:, not setBGColor:.

Use American spellings (color, initialize), and capitalise acronyms wholly — URLString, HTTPBody, PDFRepresentation — except at the start of a lowercase identifier: urlString, httpBody.

Method Names

Kind Rule

Verb phrase for actions

- (void)insertObject:atIndex:, - (void)reloadData

Noun phrase for values

- (NSUInteger)count, - (NSString *)name — no get prefix

Parameters described by keywords

- (void)sendAction:to:forAllCells:, not - (void)send:::

get only for pointer out-parameters

- (void)getRed:green:blue:alpha: — returns values by reference

Factory methods start with the class

+ (instancetype)arrayWithObjects:, + (UIColor *)redColor

Initializers start with init

- (instancetype)initWithFrame:

Booleans use is/has/should

- (BOOL)isEmpty, - (BOOL)hasSuffix:

Mutating in place vs. returning a copy

sort mutates; sortedArray… returns a new one. Likewise reverse/reversedString, lowercase/lowercaseString.

That last row is a genuine Cocoa idiom worth internalising: the -ed/-ing form returns a new object, the bare verb modifies the receiver.

Accessor Names

These are not stylistic — key-value coding searches for these exact names, so NSPredicate, NSSortDescriptor, bindings, Core Data and KVO all depend on them:

For a property name Accessor

Getter

- (NSString *)name

Boolean getter

- (BOOL)isEnabled — declare with @property (getter=isEnabled) BOOL enabled

Setter

- (void)setName:(NSString *)name

Backing ivar

_name

Validation

- (BOOL)validateName:error:

To-many count

- (NSUInteger)countOfItems

To-many access

- (id)objectInItemsAtIndex:

To-many mutation

- (void)insertObject:inItemsAtIndex:, - (void)removeObjectFromItemsAtIndex:

Declaring an ordinary @property gives you the first four automatically. See Key-Value Coding and Observing.

Delegate Method Names

A delegate method’s first argument is the sender, and the selector reads as a sentence about what happened:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)options;
- (void)downloaderDidFinish:(MYKDownloader *)downloader;      // no argument beyond the sender
Verb form Meaning

should…

Asks permission; returns BOOL. - (BOOL)textFieldShouldReturn:

will…

About to happen; the delegate may prepare.

did…

Has happened; the delegate reacts.

…ForRowAtIndexPath: (a noun phrase)

A data-source request for a value.

When the sender is the only argument, run the class name into the selector without a colon-keyword: downloaderDidFinish: rather than downloader:didFinish: with nothing else. See Protocols and Delegation.

Constants and Notifications

// Prefer typed constants to #define.
extern NSString * const MYKDefaultUserAgent;
extern const NSTimeInterval MYKDefaultTimeout;

// Enumerations: prefix each case with the type name.
typedef NS_ENUM(NSInteger, MYKDownloadState) {
    MYKDownloadStateIdle,
    MYKDownloadStateRunning,
    MYKDownloadStateFinished
};

typedef NS_OPTIONS(NSUInteger, MYKDownloadOptions) {
    MYKDownloadOptionsNone           = 0,
    MYKDownloadOptionsAllowCellular  = 1 << 0,
    MYKDownloadOptionsResumable      = 1 << 1
};

// Notifications: <Prefix><Class><Did|Will><Event>Notification
extern NSNotificationName const MYKDownloaderDidFinishNotification;
extern NSNotificationName const MYKDownloaderWillStartNotification;

// Error domains: reverse DNS.
extern NSErrorDomain const MYKErrorDomain;

Note NSString * const, not const NSString * — the former is a constant pointer, which is what you want.

Prefixes

With no namespaces, a two-or-three-letter prefix is how name collisions are avoided. Two-letter prefixes are reserved by Apple (NS, UI, CG, CA, AV, MK) — use three or more of your own, on classes, protocols, C functions, constants, typedefs and enum cases alike, and a lowercase prefix_ on every category method. See Modules, Frameworks and Code Organization.

Formatting

Apple publishes no formal formatting standard, but the conventions visible throughout its own headers and sample code are consistent:

// Opening brace on the same line for methods and control structures.
- (void)processItems:(NSArray<Item *> *)items {
    for (Item *item in items) {
        if (item.isReady) {
            [self process:item];
        } else {
            [self defer:item];
        }
    }
}

// Always brace single-statement bodies.
if (error) { return nil; }

// Pointer asterisk binds to the variable.
NSString *name;

// A space after the method-type sign, none inside the brackets.
- (void)doThing;
[object doThing];

// Break long message sends by aligning the colons.
[self downloadURL:url
    configuration:configuration
       completion:^(NSData *data, NSError *error) {
    …
}];

Beyond that: keep lines to roughly 100-120 characters, group related methods under #pragma mark - headings, and let clang-format enforce whatever the project settles on rather than arguing about it. See Build and Tooling.

Documentation Comments

Xcode renders doc comments as Quick Help (⌥-click a symbol) and in the code-completion popup. Two syntaxes are accepted; the /// form is the modern one:

/// Downloads the resource at the given URL.
///
/// The completion handler is called on an arbitrary queue. Dispatch to the main
/// queue yourself before touching the UI.
///
/// @param url The resource to download. Must be an HTTP or HTTPS URL.
/// @param completion Called once, with either @c data or @c error non-nil.
/// @return A token that can be passed to @c -cancelDownloadWithToken: .
/// @note Cancellation is best-effort.
/// @warning Passing a file URL raises an exception.
/// @see -cancelDownloadWithToken:
- (MYKDownloadToken *)downloadURL:(NSURL *)url
                       completion:(void (^)(NSData * _Nullable data,
                                            NSError * _Nullable error))completion;

The equivalent block form:

/**
 Downloads the resource at the given URL.

 @param url The resource to download.
 @return A cancellation token.
 */
Tag Use

@param name

Describe a parameter.

@return

Describe the return value.

@note / @warning

A callout, rendered as a highlighted box.

@see

A cross-reference.

@c / @code … @endcode

Inline code / a code block.

@discussion

Extended prose after the summary.

Document every public declaration; leave private helpers to their names unless something is genuinely surprising. Doc comments carry over into Swift, so they are part of the interop surface too.

HeaderDoc is Apple’s older tool for generating HTML from these comments; the Doxygen-style tags above are what Xcode itself parses and are the practical choice today.

Deprecation and Availability

- (void)oldMethod
    API_DEPRECATED("Use -newMethod instead", ios(9.0, 15.0), macos(10.11, 12.0));

- (void)modernMethod API_AVAILABLE(ios(15.0), macos(12.0));

@property (nonatomic) NSInteger legacyCount
    __attribute__((deprecated("Use -count instead")));

Always name the replacement in the message — a deprecation warning that does not say what to use instead merely annoys.

Cocoa Design Patterns

Six patterns account for most of the structure of a Cocoa application.

Delegation

One-to-one hand-off of decisions or events, via a weak protocol-typed property. The most pervasive pattern in the frameworks, and the usual alternative to subclassing. See Protocols and Delegation.

Target-Action

A control stores a target object and a selector, and sends that message when something happens. Loosely coupled and configurable in Interface Builder:

[button addTarget:self
           action:@selector(buttonTapped:)
 forControlEvents:UIControlEventTouchUpInside];

- (IBAction)buttonTapped:(id)sender { … }

IBAction is a typedef for void that marks the method for Interface Builder; IBOutlet does the same for properties.

Notifications

One-to-many broadcast through NSNotificationCenter, with no coupling in either direction. Use when several unrelated objects care about an event. See Key-Value Coding and Observing.

Singleton via dispatch_once

+ (instancetype)sharedManager {
    static MYKManager *shared = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shared = [[self alloc] init];
    });
    return shared;
}

Name it shared… or default…, per Cocoa convention. Singletons are easy to overuse — they make testing harder and hide dependencies, so prefer passing a dependency in where you can, and reserve the pattern for genuinely process-wide resources.

MVC, and Its Variants

Cocoa’s architecture is Model-View-Controller: the model holds data and business rules, the view displays and accepts input, and the controller mediates — the model and view never refer to each other directly. Cocoa supplies the mediation machinery: delegation, target-action, notifications and KVO are all controller-layer glue.

Variant Difference

MVC

The controller mediates. Cocoa’s default; view controllers grow large if not disciplined.

MVP

The presenter holds all presentation logic and the view is passive, which makes the presenter testable without a UI.

MVVM

A view model exposes presentation-ready values, bound to the view (via KVO, or a reactive library). Reduces controller size and tests well.

VIPER / Clean

Further decomposition into interactor, presenter, entity, router. More files, clearer responsibilities; usually only worth it on large teams.

The practical advice is the same across all of them: keep view controllers thin by moving networking, parsing, persistence and formatting into their own objects, whatever you call the result.

Others Worth Recognising

Class clusters (a public abstract facade over private concrete subclasses — NSString, NSArray; see Inheritance and Polymorphism), categories for extending classes you do not own, blocks as completion handlers, and the responder chain for event propagation through a view hierarchy.

See Also