Mastering Objective‑C Message Forwarding to Prevent “Unrecognized Selector” Crashes
This article explains why the “Unrecognized selector sent to instance xxx” crash occurs in Objective‑C, outlines the three stages of the runtime message‑forwarding process, and provides concrete code examples for dynamic method resolution, fast forwarding, and standard forwarding to reliably prevent such crashes in iOS apps.
1. How the Crash Occurs
In Objective‑C, method calls are message sends; if the runtime cannot find a selector in the class hierarchy, it follows the message‑forwarding process and eventually raises the “Unrecognized selector sent to instance xxx” crash.
Key steps in the forwarding process Dynamic method resolution : The runtime sends resolveInstanceMethod: to the class; returning YES after adding a method prevents the crash. Fast forwarding : If forwardingTargetForSelector: returns a non‑nil object, the message is sent to that object. Standard forwarding : The runtime obtains a method signature via methodSignatureForSelector: and then calls forwardInvocation: . If no signature is found, doesNotRecognizeSelector: is invoked, causing the crash.
2. Ways to Avoid the Crash
Because the runtime gives a chance to intervene before the final crash, you can implement one of the following strategies.
2.1 Implement Dynamic Method Resolution
Override resolveInstanceMethod: in NSObject and use class_addMethod to add the missing implementation at runtime.
+ (BOOL)resolveInstanceMethod:(SEL)sel {
NSLog(@"resolve instance method: %@", NSStringFromSelector(sel));
BOOL resolved = [super resolveInstanceMethod:sel];
if (!resolved) {
class_addMethod([self class], sel, (IMP)_dynamic_method_imp_, "v@:");
return YES;
}
return resolved;
}2.2 Use Fast Forwarding
If you prefer not to add methods dynamically, implement forwardingTargetForSelector: to return a proxy object that can handle the selector.
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(@"forwarding target for selector: %@", NSStringFromSelector(aSelector));
id cls = [super forwardingTargetForSelector:aSelector];
if (cls == nil) {
ForwardProxy *p = [[ForwardProxy alloc] init];
if ([p respondsToSelector:aSelector]) {
return p;
}
}
return cls;
}2.3 Implement Standard Forwarding
Provide a non‑nil methodSignatureForSelector: and handle the invocation in forwardInvocation: to prevent the crash.
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSLog(@"method signature for selector: %@", NSStringFromSelector(aSelector));
NSMethodSignature *ms = [super methodSignatureForSelector:aSelector];
if (ms == nil) {
ms = [ForwardProxy instanceMethodSignatureForSelector:@selector(missMethod)];
}
return ms;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
NSLog(@"forward invocation: %@", anInvocation);
if (anInvocation) {
[self missTarget:[anInvocation target] withSelector:[anInvocation selector]];
}
}Note: Do not call super forwardInvocation: inside your implementation, otherwise the app will still crash.
3. Summary
By creating subclasses of NSObject or UIViewController (e.g., ForwardNSObject, ForwardUIViewController) that implement the above forwarding methods, you can centralize crash‑avoidance logic for the entire project.
Use macros to enable these safeguards only in release builds, while keeping the crashes visible during development for early fixing.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tencent TDS Service
TDS Service offers client and web front‑end developers and operators an intelligent low‑code platform, cross‑platform development framework, universal release platform, runtime container engine, monitoring and analysis platform, and a security‑privacy compliance suite.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
