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, 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 |
|
Noun phrase for values |
|
Parameters described by keywords |
|
|
|
Factory methods start with the class |
|
Initializers start with |
|
Booleans use |
|
Mutating in place vs. returning a copy |
|
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 |
|
Boolean getter |
|
Setter |
|
Backing ivar |
|
Validation |
|
To-many count |
|
To-many access |
|
To-many mutation |
|
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 |
|---|---|
|
Asks permission; returns |
|
About to happen; the delegate may prepare. |
|
Has happened; the delegate reacts. |
|
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 |
|---|---|
|
Describe a parameter. |
|
Describe the return value. |
|
A callout, rendered as a highlighted box. |
|
A cross-reference. |
|
Inline code / a code block. |
|
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
-
Protocols and Delegation — delegate naming and the pattern in full.
-
Key-Value Coding and Observing — why accessor naming is functional, not cosmetic.
-
Modules, Frameworks and Code Organization — prefixes and header hygiene.
-
Build and Tooling —
clang-formatand the analyzer.