Creating Objects: alloc, init, and Why They're Always Chained
Explain the two-phase object creation process in Objective-C — alloc followed by init — describe precisely what each step does, and explain why they are always chained into a single expression rather than called as two separate statements.
The Class Anatomy lesson used the line Person *person = [[Person alloc] init]; to create a Person object without dwelling on why it's written that particular way. This lesson slows that line down. Creating an object in Objective-C is not one operation — it's a deliberate two-step process, alloc then init, each doing a genuinely different job, and understanding what each step actually does (and why they must be chained together rather than kept as separate statements) is essential before you can safely write your own initializers in the next lesson.
Two Distinct Steps Behind One Line
Person *person = [[Person alloc] init]; looks like a single action, but it is actually two separate messages sent one after another, with the result of the first feeding directly into the second. Reading from the inside out: [Person alloc] is sent first — a message to the Person class itself (not to any instance, since none exists yet), asking it to allocate a new, empty instance. Whatever alloc returns is then immediately sent init — [<that result> init] — which sets up the object's actual usable state. The outer square brackets and the assignment to person simply capture init's return value.
It's worth being explicit about what each nested bracket pair means, since Objective-C's nested message syntax reads awkwardly at first. [Person alloc] is evaluated first, because it's the innermost expression; its result (a newly allocated, but not yet initialized, Person object) becomes the receiver of the next message, init. So the full line, read step by step, is: 'ask the Person class to allocate a new instance; then ask that new instance to initialize itself; then store whatever init hands back into the variable person.'
This two-phase shape — allocate, then initialize — is not unique to Person or to any one class; it is the universal pattern for creating any Objective-C object, from a simple NSObject subclass to complex Foundation classes like NSString or NSArray. Once you understand what alloc and init each actually do, you'll recognize [[ClassName alloc] init] everywhere in Objective-C code, because it is the pattern.
• [[Person alloc] init] is two chained messages, not one: alloc first, then init on alloc's result. • [Person alloc] is a class method sent to the Person class itself — no instance exists yet at that point. • The result of alloc immediately becomes the receiver of init. • This alloc-then-init shape is the universal object-creation pattern across all of Objective-C, not specific to Person.
What alloc Actually Does
alloc is a class method — sent to the class itself, like Person, rather than to any particular instance — and its job is narrowly defined: it asks the Objective-C runtime for a block of memory large enough to hold one instance of that class (enough room for every property and internal instance variable the class defines), zeroes out that entire block of memory, and sets the new object's internal class pointer (isa, covered conceptually in an earlier lesson) so the runtime knows 'this chunk of memory is a Person.' Then it returns a pointer to that freshly allocated object.
The crucial detail is that the object alloc returns is uninitialized, even though it isn't garbage — because the memory was zeroed, every property currently holds its type's zero value: object-type properties (like name, an NSString pointer) are nil, numeric properties (like age) are 0, and BOOL properties are NO. This is a genuinely useful guarantee — you'll never get unpredictable garbage bits the way an uninitialized plain C variable can hold — but it is not the same as being properly set up. An object fresh from alloc has no real identity yet: no name has been chosen, no meaningful starting age has been assigned, nothing that actually represents 'a particular Person' has happened.
It also matters that alloc is a class method (called with a class name as the receiver, [Person alloc]), while init, as covered next, is an instance method (called on the specific object just allocated). This distinction — some messages go to the class itself, others go to a particular instance of it — is one you'll see constantly in Objective-C, and alloc/init is the very first place it shows up: you can't call alloc on an instance (there isn't one yet), and you can't meaningfully call init on the class (init needs a specific block of memory to set up).
• alloc is a class method: sent to the class itself (e.g. [Person alloc]), not to any instance. • It allocates a zeroed block of memory sized for the class, sets the object's class pointer, and returns a pointer to it. • Because memory is zeroed, properties start at their type's zero value (nil for objects, 0 for numbers, NO for BOOL) — not random garbage. • The object from alloc alone is real memory with a real class identity, but has no meaningful state yet — it isn't properly initialized.
What init Actually Does
init is an instance method — sent to the specific object alloc just handed back — and its job is to set up that object's actual, meaningful starting state: assigning real values to properties, running any setup logic the class needs, and generally turning 'a zeroed block of memory that happens to be a Person' into 'an actual, usable Person object.' The default init provided by NSObject does very little on its own (it mostly just returns the object as-is); the real value of init comes when a class overrides it to set up its own specific state, exactly as the Person class's initializer did in the Class Anatomy lesson.
Here is the detail that catches nearly every beginner off guard: the object that init returns is not guaranteed to be the exact same object alloc returned. init's declared return type is essentially 'give back the object that should be used from here on' — and in most everyday cases that is indeed the same object alloc allocated, but Objective-C's design deliberately leaves room for init to return a different object entirely (for example, a class might return a shared, already-existing instance instead of the freshly allocated one, or — as covered in the next lesson — return nil if initialization failed). Because of this, you should never treat the object returned by alloc as the 'real' object and treat init's return value as an afterthought — the object that matters is whatever init hands back.
This is precisely why you always write [[Person alloc] init] as one chained expression, capturing only the final result, rather than splitting it into two statements with two variables. If you wrote Person *temp = [Person alloc]; Person *person = [temp init];, temp would technically still work in the vast majority of ordinary cases — but you would now be relying on an assumption (that init always returns the same object it was called on) that Objective-C does not guarantee, and that some real classes deliberately violate. Chaining the calls and only ever holding on to init's return value sidesteps the whole issue: you use the object that init says is correct, full stop, without needing to know or care whether it happens to be the same one alloc returned.
• init is an instance method: sent to the object alloc just returned, not to the class itself. • init sets up the object's real, meaningful state — assigning starting values, running setup logic. • The object init returns is not guaranteed to be the same object alloc returned — Objective-C deliberately allows init to substitute a different object. • Because of that, only the object returned by init should ever be treated as 'the real object' — never rely on the intermediate alloc result.
Why Always Chain Them
Given the previous section, the rule 'always chain alloc and init, never call them as two separate statements assigned to two separate variables' isn't a stylistic preference — it follows directly from what init is allowed to do. Person *person = [[Person alloc] init]; guarantees that person holds exactly the object you're supposed to use, because it's the direct result of init, with no separately-named alloc result hanging around that you might accidentally keep using instead.
The failure mode chaining avoids is subtle and easy to miss precisely because it usually doesn't cause a crash. If you split the calls (Person *a = [Person alloc]; Person *b = [a init];), and you then, by habit or a copy-paste mistake, kept using a somewhere later instead of b, you'd be operating on the pre-initialization object in the ordinary case where init happens to return the same object — but the moment you used that pattern with a class whose init substitutes a different object (which does happen in real Foundation and UIKit code, particularly with initializers that can fail or that return shared instances), you'd be silently working with a stale, wrong object, producing a bug that's hard to trace back to its cause.
The convention, then, is simple and absolute: always chain — [[ClassName alloc] init] — and only ever keep the final result. This isn't just idiomatic style; it's the only version of object creation that's guaranteed correct for every class, including ones you haven't looked at closely enough to know whether their init substitutes objects or not.
• Chaining guarantees you only ever keep the object init says is correct — no stray reference to the pre-init object. • Splitting alloc and init into separate statements/variables risks silently using the wrong (stale, pre-init) object if a class's init ever substitutes a different one. • This bug is subtle: it often doesn't crash, it just silently uses the wrong object. • Rule: always write [[ClassName alloc] init] as one chained expression, and keep only its final result.
Why the Two-Phase Design Exists at All
It's fair to ask why Objective-C splits object creation into two messages instead of one combined 'create and initialize' call, the way some other languages do with a single new. The answer is a deliberate separation of concerns: memory allocation (a mechanical, largely uniform operation — reserve some zeroed bytes, tag them with a class) is a completely different kind of work from initialization logic (which varies enormously from class to class and often needs parameters, validation, or fallback behavior). Keeping them as two distinct messages lets each one stay focused and lets subclasses override just the part that actually varies.
Concretely, subclasses essentially never need to override alloc — the mechanics of allocating zeroed memory for an object are the same regardless of what class it is, so NSObject's implementation of alloc handles every subclass correctly without any of them needing to touch it. What subclasses do override, constantly, is init (and the designated/convenience initializer patterns built on top of it, covered in the next lesson) — because that's where each class's own specific setup logic actually lives. If alloc and init were fused into a single step, every subclass would be forced to re-implement the memory-allocation mechanics alongside its own initialization logic, even though the mechanics never actually change.
This diagram summarizes the whole flow:
• alloc's job (mechanical, uniform) and init's job (class-specific setup logic) are different enough to deserve separate steps. • Subclasses essentially never need to override alloc — NSObject's implementation already works correctly for every subclass. • Subclasses very commonly override init, because that's where a class's own specific setup logic belongs. • Splitting the two lets each stay focused, and lets the initialization side alone support the designated/convenience patterns covered next.
Code Examples
[Person alloc] allocates and zeroes memory for a new Person, then init (Person's overridden initializer, as shown in the Class Anatomy lesson) runs immediately on that result, setting up real starting state. Only the final, chained result is kept in person.
This compiles and, for a plain Person whose init just returns self, behaves identically to the chained version. But it establishes the habit of holding onto alloc's intermediate result, which becomes a real bug risk the moment you use a class whose init can return a different object (a shared instance, or nil on failure, covered in the next lesson).
Widget has no custom init, so this example calls alloc alone to inspect the zeroed state directly. label prints as (null) because an object property zeroes to nil, and count prints as 0 because a numeric property zeroes to 0 -- predictable zero values, but not meaningful initialized state. Expected result: label=(null) count=0
Person *person = [[Person alloc] init];
NSLog(@"Created: %@, age %ld", person.name, (long)person.age);Person *allocated = [Person alloc];
Person *person = [allocated init];
// person is what you should use from here on --
// NOT allocated, even though in this case they happen to be the same object@interface Widget : NSObject
@property (nonatomic, strong) NSString *label;
@property (nonatomic, assign) NSInteger count;
@end
@implementation Widget
@end
// Elsewhere:
Widget *w = [Widget alloc]; // alloc only -- not yet initialized
NSLog(@"label=%@ count=%ld", w.label, (long)w.count);alloc, then init: Two Steps, One Chained Expression
[[Person alloc] init] chains these two messages into one expression, so the variable you keep is always the object init says is correct.
Person *a = [Person alloc]; Person *person = [a init]; // ...later, by mistake... NSLog(@"%@", a.name); // using the pre-init reference
Person *person = [[Person alloc] init]; NSLog(@"%@", person.name);
Keeping a separate reference to alloc's result invites accidentally using the wrong (potentially stale, pre-init, or even wrong-object) reference later. Chaining the calls means there is only ever one reference to hold onto: the one init actually returned.
Person *person = [Person init]; // calling init directly on the class Person *person = [[Person alloc] init];
init is an instance method meant to be sent to an already-allocated object, not to the class itself. Calling init directly on the class skips allocation entirely and either fails to compile as intended or produces undefined behavior -- there is no allocated memory for init to set up.
Person *person = [Person alloc]; // using person immediately without ever calling init NSLog(@"%@", person.name);
Using an object straight from alloc without ever calling init means you're relying on its zeroed-but-uninitialized state, skipping any setup logic the class's init is supposed to run -- properties may be at their zero value (nil/0/NO) rather than the meaningful starting state the class intends.
What does alloc actually do? A. It runs a class's custom setup logic and assigns meaningful starting values to properties B. It allocates and zeroes a block of memory for a new instance, sets its class pointer, and returns a pointer to it -- with no meaningful setup yet C. It creates a fully initialized object ready for use D. It is only used for numeric properties, not object properties
B. It allocates and zeroes a block of memory for a new instance, sets its class pointer, and returns a pointer to it -- with no meaningful setup yet — alloc's job is purely mechanical: reserve zeroed memory sized for the class and tag it with the class's identity. Any meaningful setup logic belongs to init, not alloc.
Why should [[Person alloc] init] always be written as one chained expression rather than two separate statements with two variables? A. Because splitting them is a syntax error in Objective-C B. Because init is not guaranteed to return the exact same object alloc returned, so keeping only init's result avoids accidentally referencing a stale or wrong object C. Because alloc is slower when called as a separate statement D. Because init cannot be called unless it's on the same line as alloc
B. Because init is not guaranteed to return the exact same object alloc returned, so keeping only init's result avoids accidentally referencing a stale or wrong object — Objective-C deliberately allows init to return a different object than the one alloc allocated. Chaining the calls and keeping only the final result guarantees you always use the object that's actually correct.
Immediately after [Person alloc] runs (before init), what state do a freshly allocated Person's properties hold? A. Unpredictable garbage values, same as an uninitialized C variable B. Their type's zero value -- nil for object properties, 0 for numeric properties, NO for BOOL properties C. Whatever values were used the last time any Person object was created D. A compiler error, because properties can't exist before init runs
B. Their type's zero value -- nil for object properties, 0 for numeric properties, NO for BOOL properties — alloc zeroes the memory it allocates, so every property starts at a predictable zero value for its type -- unlike a plain uninitialized C variable, but still not meaningful, class-specific starting state.
Why does Objective-C split object creation into alloc and init as two separate messages instead of one combined step? A. For historical reasons only, with no real design benefit today B. Because memory allocation is uniform mechanical work shared by every class, while initialization logic varies per class -- splitting them lets subclasses override only the part that actually varies C. Because init cannot run without a separate network request D. Because Objective-C does not support combining multiple messages
B. Because memory allocation is uniform mechanical work shared by every class, while initialization logic varies per class -- splitting them lets subclasses override only the part that actually varies — alloc's mechanics are the same for every class, so subclasses essentially never override it; init is where class-specific setup logic lives, so subclasses override it constantly. Separating the two keeps each concern focused.
[Person alloc]
│
▼
Memory/object storage
(zeroed bytes, class pointer set,
properties at zero-value: nil/0/NO)
│
▼
init
(runs setup logic, assigns
real starting state)
│
▼
Initialized object
(the value actually returned —
not necessarily the same object
alloc handed back)