“The UIResponder class does not store or set the next responder automatically, instead
returning nil by default. Subclasses must override this method to set the next responder.
UIView implements this method by returning the UIViewController object that manages it (if
it has one) or its superview (if it doesn’t); UIViewController implements the method by
returning its view’s superview; UIWindow returns the application object, and UIApplication
returns nil.”
It means that for a V, the return value of nextResponder is either the corresponding C or its
superview. Because none of M, V or C can be absent in an App, C exists fore sure, namely, there
must be a [V nextResponder] that returns a C. Besides, we can get all Vs from
recursiveDescription, so getting C from known V is approachable, then M is not far from us.
Therefore, our current target is to get C of the top cell, and it’s relatively easy; keep calling
nextResponder from cell, until a C is returned:
cy# [#0x17f92890 nextResponder]
#"<UITableViewWrapperView: 0x17eb4fc0; frame = (0 0; 320 504); gestureRecognizers =
<NSArray: 0x17ee5230>; layer = <CALayer: 0x17ee5170>; contentOffset: {0, 0};
contentSize: {320, 504}>"
cy# [#0x17eb4fc0 nextResponder]
#"<UITableView: 0x16c69e00; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers
= <NSArray: 0x17f4ace0>; layer = <CALayer: 0x17f4ac20>; contentOffset: {0, -64};
contentSize: {320, 717.5}>"
cy# [#0x16c69e00 nextResponder]
#"<UIView: 0x17ebf2b0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer:
0x17ebf320>>"
cy# [#0x17ebf2b0 nextResponder]
#"<PhoneSettingsController 0x17f411e0: navItem <UINavigationItem: 0x17dae890>, view
<UITableView: 0x16c69e00; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers =
<NSArray: 0x17f4ace0>; layer = <CALayer: 0x17f4ac20>; contentOffset: {0, -64};
contentSize: {320, 717.5}>>"
As soon as we get C, we can search in C’s header for clues of M. In this example, first we
need to locate the binary that contains PhoneSettingsController, we aren’t sure whether it
comes from Preferences.app or a certain PreferenceBundle. In this case, a simple test would be
all good:
FunMaker-5:~ root# grep -r PhoneSettingsController /Applications/Preferences.app/
FunMaker-5:~ root# grep -r PhoneSettingsController /System/Library/
Binary file /System/Library/Caches/com.apple.dyld/dyld_shared_cache_armv7s matches
grep: /System/Library/Caches/com.apple.dyld/enable-dylibs-to-override-cache: No such
file or directory
grep: /System/Library/Frameworks/CoreGraphics.framework/Resources/libCGCorePDF.dylib: No
such file or directory
grep: /System/Library/Frameworks/CoreGraphics.framework/Resources/libCMSBuiltin.dylib:
No such file or directory
grep: /System/Library/Frameworks/CoreGraphics.framework/Resources/libCMaps.dylib: No
such file or directory
grep: /System/Library/Frameworks/System.framework/System: No such file or directory