Getting Started

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 is C with Smalltalk-style object messaging bolted on. Every valid C program is a valid Objective-C program: the language adds a small set of @-prefixed directives, a square-bracket message-send syntax, and a dynamic run-time library that decides at execution time which method a message actually invokes. That "thin layer over C, dynamic dispatch at the top" design is the single fact that explains most of the rest of this reference.

What Objective-C Is

The language has exactly two halves, and keeping them apart makes it far easier to learn:

  • The C half. Types, operators, control flow, functions, pointers, struct, the preprocessor — all unchanged from C. Objective-C is a strict superset of C, so C libraries are called directly with no bridge, no marshalling and no overhead.

  • The Objective-C half. @interface/@implementation class declarations, message sends written [receiver message], protocols, categories, and a run-time library (libobjc) that resolves each message by selector at the moment it is sent.

// The C half: an ordinary function, ordinary types.
int doubled(int x) { return x * 2; }

// The Objective-C half: a message send. "length" is looked up at run time.
NSString *greeting = @"Hello";
NSUInteger n = [greeting length];

The second line is not a function call that the compiler resolves to an address. It compiles to a call to objc_msgSend(greeting, @selector(length)), and the run time finds the implementation. This is why Objective-C supports categories, method swizzling, key-value observing and message forwarding — features that a statically dispatched language cannot offer — and also why the compiler cannot catch an "unrecognized selector" mistake for you.

A Short History

Period What happened

Early 1980s

Brad Cox and Tom Love design Objective-C at Stepstone, adding Smalltalk-80’s messaging model to C so that reusable "software ICs" could be built without leaving the C toolchain.

1988

NeXT licenses the language and builds NeXTSTEP on it. The NS prefix that still decorates NSString, NSArray and the rest of Foundation dates from here.

1996-2001

Apple acquires NeXT; NeXTSTEP becomes the basis of Mac OS X, and Objective-C becomes the language of Cocoa.

2006-2007

Objective-C 2.0 ships with Mac OS X 10.5: declared properties (@property), fast enumeration (for…in), protocol @optional, and a (now removed) garbage collector.

2011

ARC — Automatic Reference Counting — moves retain/release bookkeeping into the compiler, and remains the default memory model today. Literals and subscripting (@[], @{}, @42) follow shortly after.

2014-present

Swift is announced and gradually becomes Apple’s default language. Objective-C keeps evolving where it must interoperate — nullability annotations, lightweight generics, @available, class properties — and remains in service across Apple’s own frameworks, long-lived application codebases, and any project that needs the run-time dynamism Swift deliberately does not offer.

Two features are removed and appear in this reference only as history: garbage collection (deprecated in OS X 10.8, removed in 10.11) and class posing (poseAsClass:, see Categories and Extensions). Neither is available in any current toolchain.

Objective-C Compared

Versus C++

Both add objects to C, but from opposite directions:

Objective-C C++

Dispatch

Dynamic by default — selector looked up at run time

Static by default; virtual gives single-level dynamic dispatch through a vtable

Unknown method

Run-time error (unrecognized selector), interceptable via forwarding

Compile-time error

Object model

Single inheritance + protocols; all objects are heap-allocated pointers

Multiple inheritance, templates, stack or heap allocation, value semantics

Introspection

Rich and built in — classes, methods, ivars and properties are all enumerable at run time

Minimal (typeid, RTTI)

Memory

ARC (compiler-inserted reference counting)

RAII, smart pointers, manual new/delete

The two can be mixed in one translation unit — see Objective-C++ and C Interoperability.

Versus Swift

Swift is safer and terser; Objective-C is more dynamic and has decades of shipped code behind it. Swift enforces optionality, value types and exhaustive switch at compile time, where Objective-C leans on run-time conventions (nil absorbing messages, NSError ** out-parameters). The two interoperate closely within one target — see Swift Interoperability.

Objective-C remains worth knowing for maintaining and extending existing codebases, for reading Apple’s own framework headers, for run-time-driven techniques (KVO, swizzling, proxies) that Swift cannot express natively, and for C and C++ interoperability without a bridging layer.

Toolchains

Toolchain Notes

Apple Clang (Xcode)

The reference implementation and the subject of this section. Ships with Xcode or the Command Line Tools (xcode-select --install). Supports every modern feature: ARC, modules, lightweight generics, nullability.

Clang (upstream LLVM)

Available on Linux and Windows. Supports the language, but Apple’s frameworks are not present — pair it with GNUstep for a Foundation implementation.

GCC

Retains an Objective-C front end and the GNU run time. It lags Apple Clang: no ARC on the GNU run time in practice, and no Clang modules. Suitable for legacy GNUstep code.

GNUstep

An open-source reimplementation of the OpenStep/Cocoa APIs (Foundation, AppKit) for Linux and Windows. Build flags come from gnustep-config.

File Extensions

Extension Contents

.h

Header — the public interface: @interface declarations, protocols, `typedef`s, function prototypes.

.m

Implementation — Objective-C and C source (@implementation bodies).

.mm

Implementation compiled as **Objective-C**, so C syntax is also accepted.

.pch

Prefix header, precompiled and implicitly included (rare in modern projects; prefer @import).

The Compilation Pipeline

An Objective-C translation unit travels the same route as a C one; what is distinctive is that the Objective-C constructs are lowered into ordinary C calls into libobjc, and that the run-time library must be linked in and is present at execution time.

Objective-C compilation pipeline: source through preprocessing, compilation, assembly and linking to a running process, with the Objective-C runtime library linked in and active at run time

Hello, World

#import <Foundation/Foundation.h>

int main(int argc, const char *argv[]) {
    @autoreleasepool {
        NSString *name = @"World";
        NSLog(@"Hello, %@!", name);
    }
    return 0;
}

Four things in nine lines are worth naming:

  • #import is Objective-C’s include directive — like #include, but it never includes the same file twice, so header guards are unnecessary.

  • Foundation/Foundation.h is the umbrella header of the Foundation framework, which supplies NSString, NSArray, NSLog and the rest of the value and collection types.

  • @autoreleasepool bounds the lifetime of autoreleased temporaries. Under ARC it is still required at the top of main and in tight loops; see Automatic Reference Counting.

  • %@ is the format specifier for an Objective-C object: NSLog sends it description and prints the result. See Classes and Objects.

Building and Running

With Apple Clang on macOS:

clang -fobjc-arc -fmodules -Wall -Wextra \
      -framework Foundation \
      hello.m -o hello
./hello
# 2026-01-01 12:00:00.000 hello[12345:678901] Hello, World!

With GNUstep on Linux:

clang `gnustep-config --objc-flags` \
      hello.m -o hello \
      `gnustep-config --base-libs`
./hello

gnustep-config --objc-flags emits the include paths and run-time selection flags; --base-libs emits the linker flags for libgnustep-base. Substitute gcc for clang if you must use the GNU compiler, and drop -fobjc-arc and -fmodules, which the GNU run-time configuration generally does not support.

The flag set used throughout this reference is clang -fobjc-arc -fmodules -Wall -Wextra -framework Foundation: ARC on, Clang modules on, warnings turned up. Examples note explicitly where GNUstep differs.

See Also

  • Basic Syntax and Types — the type vocabulary (id, BOOL, NSInteger, SEL) the rest of the section assumes.

  • Classes and Objects — writing your first @interface/@implementation pair.

  • Build and Tooling — the full flag reference, xcodebuild, analyzers, sanitizers and debugging.