Objective-C Blocks and GCD
Use when blocks (closures) and Grand Central Dispatch in Objective-C for concurrent programming including block syntax, capture semantics, dispatch queues, dispatch groups, and patterns for thread-safe asynchronous code.
What this skill does
# Objective-C Blocks and GCD
## Introduction
Blocks are Objective-C's closure implementation, providing anonymous functions
that capture surrounding context. Grand Central Dispatch (GCD) is Apple's
low-level API for managing concurrent operations using dispatch queues rather
than threads directly.
Blocks enable functional programming patterns, callbacks, and clean asynchronous
API design. GCD simplifies concurrency by abstracting thread management into
queues that automatically distribute work across available CPU cores. Together,
they form the foundation for modern Objective-C concurrent programming.
This skill covers block syntax and semantics, capture behavior, GCD queues and
dispatch functions, synchronization primitives, and patterns for safe concurrent
code.
## Block Syntax and Usage
Blocks are first-class objects that encapsulate code and can capture variables
from their defining scope.
```objectivec
// Basic block syntax
void (^simpleBlock)(void) = ^{
NSLog(@"Hello from block");
};
simpleBlock(); // Call block
// Block with parameters
int (^addBlock)(int, int) = ^(int a, int b) {
return a + b;
};
int result = addBlock(5, 3); // 8
// Block with return type
NSString *(^greetBlock)(NSString *) = ^NSString *(NSString *name) {
return [NSString stringWithFormat:@"Hello, %@", name];
};
NSString *greeting = greetBlock(@"Alice");
// Blocks as method parameters
- (void)fetchDataWithCompletion:
(void (^)(NSData *data, NSError *error))completion {
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Simulate network call
NSData *data = [@"response" dataUsingEncoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(data, nil);
}
});
});
}
// Using block-based API
- (void)loadData {
[self fetchDataWithCompletion:^(NSData *data, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"Data: %@", data);
}
}];
}
// Typedef for block types
typedef void (^CompletionBlock)(BOOL success);
typedef void (^DataBlock)(NSData *data, NSError *error);
typedef NSString *(^TransformBlock)(NSString *input);
- (void)performOperationWithCompletion:(CompletionBlock)completion {
// Async operation
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Work
BOOL success = YES;
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(success);
}
});
});
}
// Blocks in collections
NSArray *blocks = @[
^{ NSLog(@"Block 1"); },
^{ NSLog(@"Block 2"); },
^{ NSLog(@"Block 3"); }
];
for (void (^block)(void) in blocks) {
block();
}
// Block properties
@interface AsyncOperation : NSObject
@property (nonatomic, copy) CompletionBlock completion;
@property (nonatomic, copy) DataBlock dataHandler;
@end
@implementation AsyncOperation
@end
```
Blocks must be copied when stored in properties or collections to move them from
stack to heap storage.
## Block Capture Semantics
Blocks capture variables from their defining scope, with different behaviors for
different storage types and qualifiers.
```objectivec
// Capturing local variables
void captureExample(void) {
NSInteger x = 10;
void (^block)(void) = ^{
NSLog(@"x = %ld", (long)x); // Captures value of x
};
x = 20;
block(); // Prints "x = 10" (captured at block creation)
}
// __block qualifier for mutable capture
void mutableCaptureExample(void) {
__block NSInteger counter = 0;
void (^incrementBlock)(void) = ^{
counter++; // Can modify counter
};
incrementBlock();
incrementBlock();
NSLog(@"Counter: %ld", (long)counter); // 2
}
// Capturing self in methods
@interface Counter : NSObject
@property (nonatomic, assign) NSInteger count;
- (void)incrementAsync;
@end
@implementation Counter
- (void)incrementAsync {
// Strong capture of self
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.count++; // Captures self strongly
});
}
@end
// Weak-strong dance for self
@interface ViewController : UIViewController
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation ViewController
- (void)startTimer {
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
repeats:YES
block:^(NSTimer *timer) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
// Safe to use strongSelf
[strongSelf updateUI];
}];
}
- (void)updateUI {
NSLog(@"Updating UI");
}
- (void)dealloc {
[self.timer invalidate];
}
@end
// Capturing objects vs primitives
void objectCaptureExample(void) {
NSMutableString *string = [NSMutableString stringWithString:@"Hello"];
void (^block)(void) = ^{
[string appendString:@" World"]; // Can mutate object
NSLog(@"%@", string);
};
block(); // Prints "Hello World"
}
// Block retain cycles
@interface NetworkManager : NSObject
@property (nonatomic, copy) void (^completion)(NSData *data);
@end
@implementation NetworkManager
- (void)fetchData {
__weak typeof(self) weakSelf = self;
self.completion = ^(NSData *data) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
[strongSelf processData:data];
};
}
- (void)processData:(NSData *)data {
NSLog(@"Processing: %@", data);
}
@end
// Capturing __block objects
void blockObjectExample(void) {
__block NSMutableArray *array = [NSMutableArray array];
void (^addBlock)(id) = ^(id object) {
[array addObject:object]; // Can mutate and reassign
};
addBlock(@"Item 1");
addBlock(@"Item 2");
array = [NSMutableArray array]; // Can reassign
}
```
Use `__weak` to avoid retain cycles when capturing self, and `__block` to allow
mutation of captured variables.
## Dispatch Queues
GCD uses dispatch queues to manage concurrent execution, with serial queues
executing tasks sequentially and concurrent queues executing them in parallel.
```objectivec
// Main queue (serial, main thread)
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI
NSLog(@"On main thread");
});
// Global concurrent queues
dispatch_queue_t highPriorityQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_queue_t defaultQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t lowPriorityQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
// Async execution on global queue
dispatch_async(defaultQueue, ^{
// Background work
NSLog(@"Background work");
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI on main queue
NSLog(@"UI update");
});
});
// Custom serial queue
dispatch_queue_t serialQueue = dispatch_queue_create("com.example.serial", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
NSLog(@"Task 1");
});
dispatch_async(serialQueue, ^{
NSLog(@"Task 2");
});
// Custom concurrent queue
dispatch_queue_t concurrentQueue = dispatch_queue_create(
"com.example.concurrent", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^{
NSLog(@"Concurrent task 1");
});
dispatch_async(concurrentQueue, ^{
NSLog(@"Concurrent task 2");
});
// Synchronous dispatch (blocks until complete)
__block NSString *result;
dispatch_sync(serialQueue, ^{
result = @"Computed value";
});
NSLog(@"Result: %@", result);
// Dispatch after (delayed execution)
dispatch_after(dispatch_time(DISPARelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.