Blocks: Closures, Capture, Memory, and Asynchronous Callbacks

Master Objective-C blocks in depth — their syntax, their behavior as closures that capture surrounding variables by value, their conceptual storage classes, the copy attribute, the __block qualifier, how they cause and how to fix retain cycles, and their central role as callbacks and completion handlers in real asynchronous APIs.

Blocks are, without exaggeration, one of the most important features in all of Objective-C, and this lesson treats them with the depth that importance demands. A block is a chunk of code — with its own parameters and return value, just like a function — that you can create inline, store in a variable, pass as an argument, and call later, possibly long after the code that created it has finished running. This is what makes blocks the backbone of asynchronous programming in Objective-C: nearly every API that does something that takes time — a network request, an animation, a database query — hands you a block to run when that work finishes, rather than making you wait. Understanding blocks precisely, including the sometimes-surprising ways they interact with memory and with the variables around them, is not optional for real Objective-C work; it is foundational, and this lesson is written to leave no important corner of it untouched.

Block Syntax: The ^ Operator and Full Anatomy

A block literal is written with the caret ^ operator, which is what distinguishes block syntax from ordinary C/Objective-C syntax everywhere it appears. The simplest possible block, one that takes no parameters and returns nothing, looks like ^{ NSLog(@"Hello from a block"); }; — a caret, an optional parameter list (empty here), and a body in braces, ending in a semicolon because the whole expression is being used as a statement.

To store a block in a variable, you need a variable whose type is 'a block that takes these parameter types and returns this type,' and the syntax for that type looks unlike any other Objective-C type declaration: returnType (^blockName)(parameterTypes). The parentheses around ^blockName are not optional — they are what tells the compiler 'this identifier names a block variable,' distinguishing it from returnType blockName(parameterTypes), which would instead declare a function. Putting declaration and assignment together, the spec's own example is the clearest possible illustration:

Reading this piece by piece: void (^completion)(BOOL success) declares a variable named completion whose type is 'a block that takes one BOOL parameter and returns nothing (void).' The = then assigns it a block literal, ^(BOOL success) { NSLog(...); } — a caret, followed by the block's own parameter list (BOOL success) (this time naming the parameter, since it's the actual definition), followed by the body. Note that the block literal itself has no return type written before its ^ here because it returns void and Objective-C allows that to be inferred; when a block does return a non-void value, you may write it explicitly as ^BOOL(NSInteger x) { return x > 0; } or let the compiler infer it from the return statement — both are common in real code.

• Block literal: ^(parameters) { body } — the caret marks it as a block, not a function. • Block variable type: returnType (^variableName)(parameterTypes) — the parentheses around ^name are mandatory. • The spec's example: void (^completion)(BOOL success) = ^(BOOL success) { NSLog(@"Success: %@", success ? @"YES" : @"NO"); };

Blocks Are Closures: First-Class Values You Can Store, Pass, and Return

The word 'closure' is the precise computer-science term for what a block is, and it's worth using deliberately: a block is a self-contained chunk of executable code, bundled together ('closed over') with the values of the variables from its surrounding scope that it references. Crucially, a block is a value, just like an NSInteger or an NSString pointer is a value — you can assign it to a variable (as in the previous section), store it as a property on an object, put it into an NSArray, pass it as an argument to a method or function, and have a method or function return one as its result.

This 'block as an ordinary value you can pass around' property is what makes blocks so useful as callbacks: instead of an API forcing you to define a whole separate named method somewhere else in your file and then tell the API 'go call that method when you're done' (the older, more ceremony-heavy delegate/selector pattern), you can write the code to run when the work finishes directly inline, right where you're calling the API, capturing whatever local context you need without any extra plumbing. A method that accepts a block parameter typically declares it exactly like a block variable, just as a parameter instead of a local: - (void)fetchDataWithCompletion:(void (^)(NSData *data, NSError *error))completion; — read the same way as before, just without a name for the block variable ready to be filled in by whoever writes the argument at the call site.

• A block is a first-class value: it can be stored in a variable/property, put in a collection, passed as an argument, or returned from a method. • 'Closure' means the block carries its code together with the captured values of variables from its surrounding scope. • Blocks let you write callback code inline at the call site, instead of defining a separate named method elsewhere.

Parameters and Return Values

Blocks handle parameters and return values exactly the way ordinary C functions and Objective-C methods do, conceptually — they just use block syntax to express it. A block with parameters lists them inside the parentheses that follow the ^, with types and names just like a method signature: ^(NSInteger a, NSInteger b) { return a + b; }. Calling a block you're holding in a variable uses ordinary function-call syntax, not message-send brackets: if sum holds that block, you call it as NSInteger result = sum(3, 4);, not [sum call:3 with:4] — this is one of the few places in everyday Objective-C where you use C-style call syntax rather than square brackets, precisely because a block, unlike an object, isn't sent messages; it's invoked.

A block's return type is written before the ^ when you declare the block's type (as in void (^completion)(BOOL success), where void is the return type), and inside the block literal itself, a return statement works exactly as it does in any function — it exits the block and hands back the value to whoever called it. If a block returns nothing, return; with no value (or simply falling off the end of the block body) is fine, same as a void function. It's worth being careful and explicit about a block's declared return and parameter types especially when the block is going to be passed to, or stored by, an API you didn't write yourself, such as a completion handler parameter — the types must match exactly what that API expects, or the code will not compile.

• Block parameters: declared inside the parentheses after ^, exactly like a method's parameter list. • Calling a block variable uses plain function-call syntax: result = someBlock(arg1, arg2);, not message brackets. • A block's return type appears before its ^ in the type declaration; return inside the body works exactly as in a normal function.

Variable Capture: Blocks Snapshot Enclosing Local Variables by Value

This is the single most important, and most frequently misunderstood, behavior of Objective-C blocks: a block automatically captures the local variables from its enclosing scope that it references inside its body, and by default it captures them by value — meaning it copies the variable's value at the moment the block literal is created, not a live, ongoing reference to that variable. Once a block has captured a variable's value, changes made to the original outer variable after that point have absolutely no effect on what the block sees when it later runs.

Consider this precisely: NSInteger count = 5; void (^printCount)(void) = ^{ NSLog(@"count is %ld", (long)count); }; count = 100; printCount(); — this prints 'count is 5', not 'count is 100'. At the moment the block literal ^{ ... } was created, it captured the value of count at that instant, which was 5, and copied it into the block's own private storage. The subsequent line count = 100; only changes the original outer count variable; it has no way to reach into the block and update the copy the block took, because there is no live connection between them at all — they are now two entirely separate storage locations that happened to start with the same value.

This behavior is a direct, deliberate consequence of what a closure needs to guarantee: a block might be called immediately, or it might be stored away and called seconds, minutes, or (via a retained property) an arbitrarily long time later, quite possibly after the function that created it, and every local variable inside it, has already finished executing and been popped off the stack entirely. By copying the values it needs at creation time, the block remains safe and correct to call at any later point, completely independent of whether the variables it was created near are still 'alive' in any conventional sense.

• Blocks capture the enclosing local variables they reference, by value, at the moment the block literal is created. • A change to the original outer variable after block creation is NOT visible inside the block — the block has its own private copy. • This is what lets a block be safely called later, even after the function that created it has already returned.

Conceptual Storage Classes: Stack, Heap, and Global Blocks

Conceptually, a block literal can live in one of three places, and understanding this — even without memorizing every implementation detail — explains why some block-related bugs happen at all. A block with no captured variables at all (referencing nothing from its enclosing scope) is treated essentially like a compile-time constant and can live in global/static storage for the whole lifetime of the program, the same way a string literal does; you never need to think about its lifetime.

A block literal that does capture surrounding variables, though, is created on the stack by default, right where it's written in your code — exactly like any other local variable in that scope. This is perfectly fine and extremely common when the block is used and finished with immediately, in the same scope where it was created (for example, passed directly as an argument to a method that calls it synchronously before returning, such as many enumeration or sorting APIs). The danger appears the moment you need the block to outlive the stack frame it was created in — for instance, if you want to store it in a property so an object can call it later, or hand it to an asynchronous API that will call it only after your current function has already returned. A stack-allocated block, like any other stack-based local data, becomes invalid once its enclosing scope exits; calling it after that point is undefined behavior.

The fix is to move — 'copy' — the block to the heap, where it becomes an independent, reference-counted object with its own lifetime, exactly like any other Objective-C object such as an NSString or NSArray instance, no longer tied to the stack frame that first created it. Once on the heap, a block can be safely retained (kept alive) by a property, an array, or anything else, for as long as that owner needs it, entirely independent of whether the original function that wrote the block literal has returned. Modern Objective-C compilers under ARC automatically insert this copy in most of the common situations where it's needed (such as passing a block directly as an argument), but it remains something you must understand and sometimes trigger explicitly — which is exactly the subject of the next section.

• No captured variables → effectively global/static storage, lives for the whole program. • Captures variables → created on the stack by default, valid only while its enclosing scope is still active. • Needs to outlive its creating scope (stored in a property, used asynchronously) → must be copied to the heap to remain valid.

The copy Attribute: Why Block Properties Need It

Because a block that captures variables starts life on the stack, and a stack-based block becomes invalid the instant its creating scope exits, any property meant to hold onto a block for later use must copy that block onto the heap at the moment it's assigned — which is precisely what the copy property attribute does. The correct way to declare a property that stores a block is @property (nonatomic, copy) void (^completionHandler)(BOOL success); — note copy, not strong.

It's worth being precise about why copy, when strong is the attribute used for essentially every other object property in this course. strong only retains whatever object it's given — it does not move a stack-based block to the heap, so if the block you assign is still stack-based at assignment time, a strong property would retain a stack frame that's about to disappear, producing memory corruption when the block is eventually called. copy performs exactly the operation described in the previous section: if the block is already on the heap, copy behaves essentially like strong (a cheap retain); if it's still on the stack, copy moves it to the heap first, and only then retains it. In modern ARC code, the block you're assigning directly from a literal is frequently already heap-based thanks to the compiler's own automatic optimizations, which is why some real-world code appears to 'get away with' strong on a block property — but this is not guaranteed by the language in every situation, and relying on it is fragile. The universal, safe, idiomatic convention — followed throughout real Objective-C codebases and enforced by static analyzers — is: block properties are declared copy, full stop, not strong.

• Block properties are declared copy, not strong: @property (nonatomic, copy) void (^completionHandler)(BOOL success); • copy guarantees the block is moved to the heap if it's still stack-based, then retained; strong alone does not guarantee this. • Treat copy on a block property as mandatory convention, not an optional style preference.

The __block Storage Qualifier: Mutating a Captured Variable

Because blocks capture enclosing local variables by value, the block's own copy is, by default, read-only from inside the block's body — the compiler will not even let you write count = count + 1; inside a block that captured count normally, precisely because that assignment could only ever affect the block's private copy in a way that looks confusing and is almost never what anyone actually wants, so the compiler forbids it outright as a compile error.

The __block storage qualifier changes this. Declaring a variable as __block NSInteger count = 0; before creating a block that references it changes how that variable is captured: instead of the block taking a private, independent copy of the value, __block makes the variable itself shared storage that both the outer scope and every block that captures it read from and write to in common. Now count = count + 1; inside the block body is legal, and — critically — that change is visible to the outer scope too, and visible to any other block that also captured the same __block variable, because there's only ever one underlying storage location being shared, not separate private copies.

The most common real use of __block is exactly this kind of running total or accumulated result that a block needs to build up across possibly-repeated calls (for example, inside a block passed to an array-enumeration method that calls it once per element), or a flag that an asynchronous completion block needs to set so that code after the async call can check whether it happened. __block is powerful but should be reached for deliberately, only when a block genuinely needs to mutate something in the enclosing scope — reaching for it out of habit, on a variable a block only needs to read, adds needless shared mutable state for no benefit.

• By default, a block cannot assign to a variable it captured — the compiler rejects it as a compile-time error. • __block NSInteger count = 0; makes count shared storage: the block can read and write it, and outer code sees the block's changes. • Reach for __block only when a block genuinely needs to mutate a variable from its enclosing scope, such as an accumulator or a completion flag.

Retain Cycles: When a Block Captures self Strongly

A retain cycle is exactly the danger the earlier sections were building toward, and it is one of the most common real-world memory bugs in Objective-C code that uses blocks. It happens in a very specific, very common shape: an object (say, a NetworkManager instance) has a copy block property, e.g. self.completionHandler, and the block literal you assign to that property references self somewhere inside its body — perhaps to update one of self's own properties once the work finishes. Because blocks capture the variables they reference — and inside an instance method, self is itself just a local variable referring to the current object — the block automatically captures self, and by default, that capture is a strong reference, exactly as if the block held its own retaining pointer to the object.

Trace the ownership chain this creates: self (the NetworkManager instance) strongly owns its completionHandler property, which is the block. The block, in turn, strongly owns self, because it captured self strongly inside its body. Each object is now keeping the other alive — a retain cycle — and under ARC's reference counting, neither object's retain count can ever reach zero, because each one is still being held onto by the other, so neither is ever deallocated. This is a real memory leak, and it's easy to write completely by accident, since referencing self.someProperty or calling [self someMethod] inside a block assigned to one of self's own properties is an extremely natural, common thing to want to do.

The standard, idiomatic fix is the weak-self/strong-self pattern: immediately before creating the block, declare a weak reference to self — __weak typeof(self) weakSelf = self; — and reference weakSelf inside the block body instead of self directly. A __weak reference does not retain what it points to, so the block capturing weakSelf does not keep self alive, breaking the cycle. Then, at the top of the block's body, it's standard practice to immediately re-strengthen it — __strong typeof(self) strongSelf = weakSelf; — and use strongSelf for the rest of the block's body. This second step matters because weakSelf could, in principle, become nil partway through the block's execution if self happens to be deallocated by something else at just the wrong moment; capturing it into a local strongSelf at the very start guarantees the object stays alive for the full duration of that one block execution, while still never being the thing that caused the original retain cycle.

• Cycle shape: self owns a block property (strong via copy); the block captures self strongly inside its body → mutual ownership, memory leak. • Fix: __weak typeof(self) weakSelf = self; before the block, and reference weakSelf (not self) inside the block body. • Inside the block, re-strengthen with __strong typeof(self) strongSelf = weakSelf; so self can't be deallocated mid-execution of that one call.

Blocks as Callbacks and Completion Handlers

'Callback' and 'completion handler' both describe the same core role a block plays: code you hand to some other piece of code, to be run later, at a moment the caller doesn't directly control — typically 'when this operation is done.' A completion handler is simply the specific, extremely common flavor of callback used for operations that finish exactly once, whether that's after a fixed amount of synchronous work or after an asynchronous operation completes at some unpredictable point in the future.

The shape of a completion-handler-based API is consistent across the whole platform: a method takes a block parameter (often named completion or completionHandler), usually as its last parameter, whose signature communicates exactly what information will be available once the work is done — commonly a success/failure indicator, a result value, and/or an NSError describing what went wrong if anything did. The calling code supplies a block literal inline at the call site, and that block's body is where you write whatever should happen next, with full access — thanks to closures — to whatever local state was relevant back where the call was made.

• A callback/completion handler is a block handed to other code, to be invoked later when some operation finishes. • Typical completion-handler signature: success flag, and/or a result value, and/or an NSError describing failure. • Because of closures, the completion block body has natural access to local context from its original call site.

Blocks in Real Asynchronous APIs

Nowhere is the value of blocks clearer than in genuinely asynchronous work, where the operation's result cannot possibly be ready by the time the method call that started it returns — a network request is the textbook example, since it may take anywhere from milliseconds to many seconds, and the calling code obviously cannot simply block and wait for that on, say, the main thread without freezing the whole app's UI. A method like - (void)fetchUserWithID:(NSString *)userID completion:(void (^)(User *user, NSError *error))completion; returns immediately, having only started the network request in the background; sometime later, once the response actually arrives, the framework calls the completion block it was given, passing in either a populated User object or an NSError describing what went wrong.

Everything covered earlier in this lesson comes together in exactly this scenario: the block must be copied to the heap (usually automatically, but conceptually this is the 'stored to survive scope exit' case from earlier) so it's still valid whenever the network response eventually arrives, long after -fetchUserWithID:completion: itself has already returned; the block property inside whatever networking object holds onto it should be copy; if the completion block references self to update the calling object's own state once data arrives, the weak-self/strong-self pattern is exactly what prevents a retain cycle between that object and its own in-flight network request; and __block variables occasionally appear when a completion block needs to accumulate results across multiple async calls, such as counting how many of several parallel requests have finished so far.

• Asynchronous methods return immediately and call their completion block later, once the real result is ready. • A real async completion-handler signature commonly looks like void (^)(ResultType *result, NSError *error). • Every concept in this lesson — heap storage, copy, weak-self/strong-self, __block — routinely applies together in one real async call.

Block Type and Block Literal

The parentheses around (^blockName) are required — they mark this as a block type, not a function declaration. A void-returning block literal may omit the return type before ^; a non-void block may write it explicitly or let it be inferred from return. Calling a block uses plain function-call syntax with parentheses, not message-send square brackets.

// Block variable declaration + block literal assignment
returnType (^blockName)(parameterTypes) = ^returnType(parameters) {
    // body
    return someValue;
};

// The spec's example — a void-returning block taking a BOOL
void (^completion)(BOOL success) = ^(BOOL success) {
    NSLog(@"Success: %@", success ? @"YES" : @"NO");
};

// Calling a stored block
completion(YES);

Code Examples

completion is a variable of block type: 'a block taking one BOOL and returning void.' It's assigned a block literal, then invoked twice with plain function-call syntax, each time running the body with the given argument. Expected result: Success: YES Success: NO void (^completion)(BOOL success) = ^(BOOL success) {... };

At the moment printCount is created, it captures the value of count — 5 — into its own private storage. The later assignment count = 100 only touches the original outer variable; the block's copy is completely unaffected, which is exactly why the call below still logs 5. Expected result: count is 5 printCount(); // still prints 5, not 100

Without __block, total += amount; inside the block would be a compile error, because the block's default captured copy is read-only. Marking total as __block makes it shared storage: the block's writes are visible in the outer scope too, so total correctly accumulates to 15. Expected result: total is 15 __block NSInteger total = 0;

Common mistake: Forgetting __block here means the code will not compile at all — the compiler flags the assignment to a normally-captured variable as an error, not a silent bug.

In the first version, self owns completionHandler (a copy property), and the block captures self strongly to call -logCompletion, so self and the block keep each other alive forever — a leak. The fixed version captures only a __weak reference to self, so the block does not retain self; inside the block it is re-strengthened into a local strongSelf just long enough to safely run that one call.

__weak typeof(self) weakSelf = self;

Common mistake: Writing [self logCompletion]; directly inside a block stored on one of self's own properties creates a self -> block -> self retain cycle, silently leaking the object.

fetchUserWithID:completion: returns right away; the completion block runs later, whenever the underlying asynchronous work finishes, with either a result or an error. The call site uses weak-self/strong-self because the block references self (via strongSelf) to update UI, exactly the pattern needed to avoid a retain cycle in real async code.

completion(userDictionary, nil);

void (^completion)(BOOL success) = ^(BOOL success) {
    NSLog(@"Success: %@", success ? @"YES" : @"NO");
};

completion(YES);   // logs: Success: YES
completion(NO);    // logs: Success: NO
NSInteger count = 5;

void (^printCount)(void) = ^{
    NSLog(@"count is %ld", (long)count);
};

count = 100;   // changes the OUTER variable only

printCount();  // still prints 5, not 100
__block NSInteger total = 0;

void (^addToTotal)(NSInteger) = ^(NSInteger amount) {
    total += amount;   // legal only because total is __block
};

addToTotal(10);
addToTotal(5);

NSLog(@"total is %ld", (long)total);   // total is 15
// --- Creates a retain cycle ---
@interface NetworkManager : NSObject
@property (nonatomic, copy) void (^completionHandler)(void);
@end

@implementation NetworkManager

- (void)start {
    self.completionHandler = ^{
        [self logCompletion];   // captures self strongly: self -> block -> self
    };
}

@end

// --- Fixed with weak-self / strong-self ---
@implementation NetworkManager

- (void)start {
    __weak typeof(self) weakSelf = self;
    self.completionHandler = ^{
        __strong typeof(self) strongSelf = weakSelf;
        if (strongSelf) {
            [strongSelf logCompletion];
        }
    };
}

@end
@interface APIClient : NSObject
@property (nonatomic, copy) void (^onFetchComplete)(NSDictionary *result, NSError *error);

- (void)fetchUserWithID:(NSString *)userID
              completion:(void (^)(NSDictionary *user, NSError *error))completion;
@end

@implementation APIClient

- (void)fetchUserWithID:(NSString *)userID
              completion:(void (^)(NSDictionary *user, NSError *error))completion {
    // Work happens asynchronously; this method returns immediately.
    // Sometime later, when the response arrives, the framework calls:
    //     completion(userDictionary, nil);   // success
    // or:
    //     completion(nil, someError);        // failure
}

@end

// Call site:
__weak typeof(self) weakSelf = self;
[apiClient fetchUserWithID:@"42" completion:^(NSDictionary *user, NSError *error) {
    __strong typeof(self) strongSelf = weakSelf;
    if (error) {
        NSLog(@"Fetch failed: %@", error);
        return;
    }
    [strongSelf displayUser:user];
}];

Block Anatomy: Code, Captured Variables, and Lifetime

A block bundles its code together with the values it captured from its enclosing scope; what happens to that bundle over time — whether it stays valid, gets copied to the heap, or creates a retain cycle — is entirely a question of lifetime and ownership.

Block
 │
 ├── Code
 └── Captured Variables
          ↓
     Lifetime / Ownership

Important Rules

Block type syntax: returnType (^name)(paramTypes); the parentheses around ^name are mandatory.

Blocks capture referenced local variables by value by default — a later change to the outer variable is not visible inside the block.

A block capturing variables starts on the stack; it must be copied to the heap to remain valid beyond its creating scope.

Block properties are declared copy, not strong, so a stack-based block is safely moved to the heap when stored.

Use __block only when a block genuinely needs to write to a variable from its enclosing scope.

A block stored in a property owned by self, that also captures self strongly, creates a retain cycle — break it with weak-self/strong-self.

Blocks Are Everywhere in Real Objective-C Code

Once you start looking, blocks are the connective tissue of nearly every non-trivial Objective-C program: animation APIs take a block describing what should change and another block to run when the animation finishes; array and dictionary enumeration methods take a block called once per element; networking libraries take a completion block for every request; notification and observation APIs let you register a block to run whenever something happens, instead of a separate observer method. Every one of the concepts in this lesson — capture-by-value, copy, __block, and especially the weak-self/strong-self retain-cycle fix — shows up constantly in real production code, which is exactly why the spec calls blocks mandatory: skipping any of these leaves genuine, common bugs (frozen UIs from accidentally-synchronous work, silently leaked objects from retain cycles, 'stale value' bugs from misunderstanding capture) waiting to happen in your very first real project.

@property (nonatomic, strong) void (^completionHandler)(BOOL success);

@property (nonatomic, copy) void (^completionHandler)(BOOL success);

strong alone does not guarantee a stack-based block gets moved to the heap; copy does, and is the universal, idiomatic attribute for block properties.

self.completionHandler = ^{ [self doSomething]; }; // inside a method on self

__weak typeof(self) weakSelf = self; self.completionHandler = ^{ __strong typeof(self) strongSelf = weakSelf; [strongSelf doSomething]; };

Capturing self strongly inside a block stored on one of self's own properties creates a self -> block -> self retain cycle; capturing a __weak reference to self, then re-strengthening it inside the block body, avoids the cycle while keeping self alive for that one call.

NSInteger x = 5; void (^b)(void) = ^{ NSLog(@"%ld", (long)x); }; x = 99; b(); // assuming this logs 99

Understand that b() still logs 5 — the block captured x's value (5) at creation time, and the later assignment x = 99 has no effect on the block's own copy.

Blocks capture referenced local variables by value at the moment the block literal is created, not by live reference, so subsequent changes to the outer variable are invisible inside the block.

NSInteger total = 0; void (^add)(NSInteger) = ^(NSInteger n) { total += n; }; // compile error

__block NSInteger total = 0; void (^add)(NSInteger) = ^(NSInteger n) { total += n; };

A normally-captured variable is read-only inside a block; assigning to it is a compile-time error. Marking the variable __block makes it shared, mutable storage the block is allowed to write to.

Passing a stack-allocated block literal into a property or asynchronous API and assuming it will still be valid whenever that API finally calls it, without ever thinking about copy/heap storage.

Recognize that a block needing to outlive its creating scope (stored in a copy property, or handed to an async API) must exist on the heap, and rely on copy (or an explicit copy) to guarantee that.

A block that captures variables is created on the stack by default and becomes invalid once its enclosing scope exits; only a heap copy (via a copy property, or an explicit [block copy]) is safe to call later, from an async callback or after being stored.

What does the ^ operator signify in Objective-C block syntax? A. Bitwise XOR, same as in plain C B. That the following expression is a block literal (or, in a type, that the identifier names a block) C. A pointer to a function, identical to a C function pointer D. An error-handling marker used only with NSError

B. That the following expression is a block literal (or, in a type, that the identifier names a block) — The caret is the syntax that introduces a block literal, and in a type declaration like void (^name)(BOOL), the parenthesized ^name marks name as a variable of block type.

Given NSInteger x = 5; void (^b)(void) = ^{ NSLog(@"%ld", (long)x); }; x = 42; b();, what does calling b() print? A. 42, because the block reads x live from the enclosing scope B. 5, because the block captured x's value at the moment the block literal was created C. It fails to compile D. 0, because x was never actually captured

B. 5, because the block captured x's value at the moment the block literal was created — Blocks capture referenced local variables by value at creation time. The block's own copy of x is 5, permanently, regardless of the later assignment x = 42 to the original outer variable.

Why must a block that will be stored in a property or handed to an asynchronous API typically end up on the heap? A. Heap blocks run faster than stack blocks B. A block that captures variables is created on the stack by default, and a stack allocation becomes invalid once its enclosing scope exits C. Only heap-allocated blocks are allowed to have parameters D. Objective-C requires every object, including blocks, to live on the heap at all times with no exceptions

B. A block that captures variables is created on the stack by default, and a stack allocation becomes invalid once its enclosing scope exits — A capturing block literal starts life on the stack, tied to its enclosing scope. If it needs to be called later — after that scope has already exited — it must first be copied to the heap, where it becomes an independent, reference-counted object.

Why is a block property conventionally declared with copy rather than strong? A. copy and strong are exact synonyms for block properties, so it doesn't matter B. copy is required by Apple's App Store review guidelines only C. copy guarantees a stack-based block is moved to the heap before being retained; strong alone does not guarantee this D. strong cannot be used with any block type, ever, as a matter of syntax

C. copy guarantees a stack-based block is moved to the heap before being retained; strong alone does not guarantee this — If the assigned block is still stack-based, strong would retain a soon-to-be-invalid stack allocation; copy moves it to the heap first (if needed) and then retains it, which is why copy is the safe, idiomatic choice.

What does marking a captured variable __block change? A. It makes the variable capture by reference/shared storage instead of by value, allowing the block to both read and write it, visibly to the outer scope B. It makes the variable a global variable accessible from any file C. It forces the block itself onto the stack rather than the heap D. It has no functional effect; it is purely documentation

A. It makes the variable capture by reference/shared storage instead of by value, allowing the block to both read and write it, visibly to the outer scope — __block changes how the variable is captured: instead of a private, read-only copy, the variable becomes shared storage that both the block and the enclosing scope read from and write to, so writes inside the block are visible outside it and vice versa.

How does a retain cycle typically form between an object and a block it owns? A. The object owns the block strongly (e.g. via a copy property), and the block captures self strongly inside its body, so each keeps the other alive B. Retain cycles cannot happen with blocks, only with delegate patterns C. The block copies the object's ivars by value, which somehow doubles its retain count D. It only happens if the block is declared __block

A. The object owns the block strongly (e.g. via a copy property), and the block captures self strongly inside its body, so each keeps the other alive — When self owns a block (typically via a copy property) and that block references self, the default strong capture of self means self owns the block and the block owns self — a mutual retain cycle that leaks both.

What is the purpose of writing __strong typeof(self) strongSelf = weakSelf; as the first line inside a block that used weak-self capture? A. It re-creates the retain cycle intentionally, which is required for the block to work B. It is purely stylistic and has no functional effect on memory safety C. It briefly and safely keeps self alive for the duration of that one block execution, guarding against self being deallocated mid-execution, without being the strong reference that caused the original cycle D. It converts the block itself from a heap block back into a stack block

C. It briefly and safely keeps self alive for the duration of that one block execution, guarding against self being deallocated mid-execution, without being the strong reference that caused the original cycle — weakSelf could become nil if self is deallocated elsewhere between the block being scheduled and it actually running. Capturing it into a local strongSelf at the top of the block body guarantees a stable, non-nil reference for that one execution, while the weak capture (not a strong one) is what avoided creating the retain cycle in the first place.

Write a Counter class with a copy block property named onChange of type void (^)(NSInteger newValue), and a method -increment that adds 1 to an internal NSInteger ivar and then calls self.onChange with the new value, if onChange is not nil. Then write a call site that sets counter.onChange using weak-self/strong-self and logs the new value.

// Counter.h @interface Counter : NSObject @property (nonatomic, copy) void (^onChange)(NSInteger newValue); - (void)increment; @end // Counter.m @interface Counter () @property (nonatomic, assign) NSInteger value; @end @implementation Counter - (void)increment { self.value += 1; if (self.onChange) { self.onChange(self.value); } } @end // Call site (e.g. inside some other object's method) Counter *counter = [[Counter alloc] init]; __weak typeof(self) weakSelf = self; counter.onChange = ^(NSInteger newValue) { __strong typeof(self) strongSelf = weakSelf; if (strongSelf) { NSLog(@"Counter changed to %ld", (long)newValue); } }; [counter increment]; // logs: Counter changed to 1

Declare the block property with copy (not strong). Inside -increment, guard the call with if (self.onChange) { self.onChange(value); }. At the call site, capture __weak typeof(self) weakSelf before assigning the block, and re-strengthen it with __strong typeof(self) strongSelf inside the block body before using self's members.