オブジェクトがあり、それが応答するすべてのセレクターを一覧表示したいと考えています。これは完全に可能であるように思えますが、API を見つけるのに苦労しています。
7 に答える
これは、ランタイム C 関数に基づくソリューションです。
class_copyMethodList は、オブジェクトから取得可能な Class オブジェクトを指定すると、クラス メソッドのリストを返します。
#import <objc/runtime.h>
[..]
SomeClass * t = [[SomeClass alloc] init];
int i=0;
unsigned int mc = 0;
Method * mlist = class_copyMethodList(object_getClass(t), &mc);
NSLog(@"%d methods", mc);
for(i=0;i<mc;i++)
NSLog(@"Method no #%d: %s", i, sel_getName(method_getName(mlist[i])));
/* note mlist needs to be freed */
通常は、コードをデバッグ コードでごちゃごちゃにする代わりに、コンソールでそれを行いたいと思うでしょう。これは、lldb でのデバッグ中にそれを行う方法です。
(オブジェクト t を仮定)
p int $num = 0;
expr Method *$m = (Method *)class_copyMethodList((Class)object_getClass(t), &$num);
expr for(int i=0;i<$num;i++) { (void)NSLog(@"%s",(char *)sel_getName((SEL)method_getName($m[i]))); }
これは Swift でも可能です。
let obj = NSObject()
var mc: UInt32 = 0
let mcPointer = withUnsafeMutablePointer(&mc, { $0 })
let mlist = class_copyMethodList(object_getClass(obj), mcPointer)
print("\(mc) methods")
for i in 0...Int(mc) {
print(String(format: "Method #%d: %s", arguments: [i, sel_getName(method_getName(mlist[i]))]))
}
出力:
251 methods
Method #0: hashValue
Method #1: postNotificationWithDescription:
Method #2: okToNotifyFromThisThread
Method #3: fromNotifySafeThreadPerformSelector:withObject:
Method #4: allowSafePerformSelector
Method #5: disallowSafePerformSelector
...
Method #247: isProxy
Method #248: isMemberOfClass:
Method #249: superclass
Method #250: isFault
Method #251: <null selector>
iOS 9.2、Xcode バージョン 7.2 (7C68) を実行する 6s シミュレーターでテスト済み。
このようなものが機能するはずです (興味のあるオブジェクトに入れるだけです)。たとえば、デリゲートであるオブジェクトがあり、利用可能な「フック」を知りたい場合、これはメッセージを出力してその手がかりを提供します:
-(BOOL) respondsToSelector:(SEL)aSelector {
printf("Selector: %s\n", [NSStringFromSelector(aSelector) UTF8String]);
return [super respondsToSelector:aSelector];
}
これはiPhone Developer's Cookbookで発見したので、信用できないことに注意してください。たとえばUIViewController
、プロトコルを実装するから取得した出力<UITableViewDelegate, UITableViewDataSource>
:
Selector: tableView:numberOfRowsInSection:
Selector: tableView:cellForRowAtIndexPath:
Selector: numberOfSectionsInTableView:
Selector: tableView:titleForHeaderInSection:
Selector: tableView:titleForFooterInSection:
Selector: tableView:commitEditingStyle:forRowAtIndexPath:
Selector: sectionIndexTitlesForTableView:
Selector: tableView:sectionForSectionIndexTitle:atIndex:
...
...
etc.,etc.
スーパークラスのセレクターも取得したい場合は、次のようにループできます。
Class c = [myObject class];
while (c != nil) {
int i = 0;
unsigned int mc = 0;
Method* mlist = class_copyMethodList(c, &mc);
NSLog(@"%d methods for %@", mc, c);
for(i = 0; i < mc; i++) {
const char* selName = sel_getName(method_getName(mlist[i]));
NSLog(@"Method #%d: %s", i, selName);
}
free(mlist);
c = [c superclass];
}