What blocks are
A block is Objective-C's closure type, declared with the caret syntax ^(NSInteger x) { return x * 2; }, and assigned to a variable using a block type like NSInteger (^doubler)(NSInteger) = ^(NSInteger x) { return x * 2; };. Blocks capture the variables they reference from their enclosing scope by value at the time the block literal is created, meaning a local int captured inside a block reflects its value when the block was defined, not any later change to that same local variable outside the block.
Cricket analogy: A block capturing currentScore by value is like a commentator jotting down the score on a card the moment they start a sentence — even if the score changes mid-sentence, their captured note still reads the earlier number.
The __block qualifier
To let a block modify a captured local variable and have that change visible outside the block (or across multiple invocations of the same block), you must declare the variable with the __block storage qualifier, such as __block NSInteger counter = 0;, which moves the variable onto the heap (conceptually) so the block holds a reference to the actual variable rather than a snapshot copy. This is essential for patterns like accumulating a running total inside an enumeration block, e.g., [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { total += [obj integerValue]; }];, where total must be declared __block to compile and behave correctly.
Cricket analogy: __block NSInteger totalRuns is like a shared physical scoreboard every fielder can see and update live during the innings, rather than each fielder carrying their own private printed copy of the score.
Retain cycles: self and __weak
Under ARC, if a block referenced by an object's property (or ivar) captures self directly — for example self.completionHandler = ^{ [self doSomething]; }; — the block strongly retains self while self strongly retains the block via its property, creating a retain cycle that leaks memory because neither object's retain count can ever reach zero. The standard fix is to capture a weak reference outside the block and use it inside: __weak typeof(self) weakSelf = self; self.completionHandler = ^{ [weakSelf doSomething]; };, optionally re-strengthening it inside the block with __strong typeof(self) strongSelf = weakSelf; to avoid the object deallocating mid-execution of a multi-line block.
Cricket analogy: A block strongly capturing self is like a bowler and a specific fielder each refusing to leave the ground until the other does — a __weak reference is like the fielder agreeing to head to the pavilion once play ends, breaking the standoff.
@interface DataLoader : NSObject
@property (nonatomic, copy) void (^completionHandler)(NSArray *results);
- (void)loadDataThenNotify;
@end
@implementation DataLoader
- (void)loadDataThenNotify {
// AVOID: strong capture of self creates a retain cycle via completionHandler
// self.completionHandler = ^(NSArray *results) { [self process:results]; };
__weak typeof(self) weakSelf = self;
self.completionHandler = ^(NSArray *results) {
__strong typeof(self) strongSelf = weakSelf;
if (!strongSelf) return; // self was already deallocated
[strongSelf process:results];
};
[self performFetchWithCompletion:self.completionHandler];
}
- (void)process:(NSArray *)results {
NSLog(@"Processing %lu results", (unsigned long)results.count);
}
- (void)performFetchWithCompletion:(void (^)(NSArray *))completion {
NSArray *fakeResults = @[@1, @2, @3];
completion(fakeResults);
}
@end
// __block example: accumulating inside enumeration
NSArray<NSNumber *> *values = @[@10, @20, @30];
__block NSInteger total = 0;
[values enumerateObjectsUsingBlock:^(NSNumber *obj, NSUInteger idx, BOOL *stop) {
total += obj.integerValue;
}];
NSLog(@"Total: %ld", (long)total);Blocks stored as properties should be declared copy, not strong. A block literal may initially live on the stack; copying moves it to the heap so it remains valid after the enclosing scope that created it returns.
Block types can be simplified with a typedef, e.g. typedef void (^CompletionHandler)(NSArray *results);, which makes method signatures and property declarations involving blocks far more readable than repeating the full block syntax everywhere.
- Blocks are closures declared with
^that capture surrounding variables by value at creation time. - The
__blockqualifier lets a block mutate a captured variable, with changes visible outside the block too. - Block properties should be declared
copyto ensure the block is moved to the heap and stays valid. - Capturing self strongly inside a block stored on self creates a retain cycle under ARC.
- The standard fix is
__weak typeof(self) weakSelf = self;used inside the block instead of self directly. - Re-strengthening with
__strong typeof(self) strongSelf = weakSelf;guards against self deallocating mid-block. - A block typedef improves readability for block types used repeatedly across method signatures.
Practice what you learned
1. By default, how does an Objective-C block capture a local variable from its enclosing scope?
2. What does declaring a variable with __block accomplish?
3. Why does storing a block that captures self on a self property typically create a retain cycle?
4. What is the purpose of re-strengthening a weak self reference inside a block with __strong typeof(self) strongSelf = weakSelf?
5. Why should block-typed properties be declared with the `copy` attribute rather than `strong`?
Was this page helpful?
You May Also Like
Methods and Message Passing
Explore how Objective-C methods work as messages sent to objects at runtime, including selectors, method signatures, and dynamic dispatch.
Class Methods vs Instance Methods
Learn the difference between Objective-C's + class methods and - instance methods, and when to use each in real-world class design.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics