Step 1 of 5 · Reading · ~3 min
Learn
Collections, Control Flow, Selectors
In Objective-C, methods are selectors — symbolic representations of method names. They let you store, pass, and dynamically dispatch method calls.
Selector basics
SEL action = @selector(uppercaseString);
SEL is just a name. You can apply it to any object:
NSString *s = @"hello";
if ([s respondsToSelector:@selector(uppercaseString)]) {
NSString *upper = [s performSelector:@selector(uppercaseString)];
printf("%s\n", [upper UTF8String]);
}
@selector(name:)— get a selector for a method (note the colon for methods with args)respondsToSelector:— check if object has this methodperformSelector:— call by selector
Selectors with arguments
[s performSelector:@selector(stringByAppendingString:) withObject:@" world"]
// "hello world"
performSelector:withObject:withObject: for two args. Beyond two: use NSInvocation (more verbose).
Storing selectors
Dispatch tables become possible:
NSDictionary *handlers = @{
@"uppercase": [NSValue valueWithPointer:@selector(uppercaseString)],
@"lowercase": [NSValue valueWithPointer:@selector(lowercaseString)],
@"reverse": [NSValue valueWithPointer:@selector(stringByReversingString)]
};
Target-action pattern
Classic Cocoa:
[button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
// On click, [self buttonClicked:button] is called.
This decoupling is fundamental to Cocoa's MVC.
Blocks (modern alternative)
Objective-C 2.0 (with C extensions) added blocks — lambda expressions. Most modern Cocoa code uses blocks instead of selectors:
int (^add)(int, int) = ^int(int a, int b) {
return a + b;
};
int result = add(3, 4); // 7
The ^ is the block syntax. int (^add)(int, int) is a block-pointer type: "block taking two ints, returning int".
Blocks capture variables:
int multiplier = 5;
int (^times)(int) = ^int(int n) { return n * multiplier; };
times(3); // 15
Blocks for collection iteration:
NSArray *nums = @[@1, @2, @3];
[nums enumerateObjectsUsingBlock:^(NSNumber *n, NSUInteger idx, BOOL *stop) {
printf("%lu: %d\n", idx, [n intValue]);
}];
Sorting with a block:
NSArray *sorted = [nums sortedArrayUsingComparator:^NSComparisonResult(NSNumber *a, NSNumber *b) {
return [b compare:a]; // descending
}];
This judge cannot compile blocks. Its Objective-C toolchain is built without
-fblocks, so every^literal above fails withblocks support disabled - compile with -fblocks. Read the block sections for the concept — you will meet blocks constantly in real Cocoa and they are the direct ancestor of Swift closures — but reach for selectors when you write code here.
Selectors vs blocks
- Selectors — older, used in target-action, NSTimer, KVO
- Blocks — newer, much more common in modern code, can capture variables
Swift inherited blocks as closures — let f: (Int) -> Int = { x in x * 2 }. They're the same machinery underneath.
Why this matters
Objective-C's dynamism (selectors, message forwarding, dynamic typing) is what makes:
- Auto-generated UIs (Interface Builder)
- KVO (Key-Value Observing) for reactive code
- Dependency injection without DI frameworks
- Mocking for tests
Understanding selectors is essential for reading legacy Cocoa code and writing extensions to NSObject behavior.
Your exercise
Give a Doubler class one method, take that method as a SEL with @selector(...),
and invoke it through performSelector:withObject: rather than by writing the message
out directly. That indirection is the whole point: the call site never names the method.
The mistake the grader catches: performSelector:withObject: traffics in id, not in
primitives. Pass a bare int and the runtime reads it as a pointer. Box the input with
[NSNumber numberWithInt:n] on the way in and unbox with intValue on the way out.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…