简体   繁体   English

列出 Objective-C 对象的选择器

[英]List selectors for Objective-C object

I have an object, and I want to list all the selectors to which it responds.我有一个对象,我想列​​出它响应的所有选择器。 It feels like this should be perfectly possible, but I'm having trouble finding the APIs.感觉这应该是完全可能的,但是我在找到 API 时遇到了麻烦。

This is a solution based on the runtime C functions: 这是一个基于运行时C函数的解决方案:

class_copyMethodList returns a list of class methods given a Class object obtainable from an object. 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 */

I think usually you'll want to do that in the console, instead of cluttering your code with debug code. 我想通常你会想在控制台中这样做,而不是用调试代码混乱代码。 This is how you can do that while debugging in lldb: 这是在lldb中调试时如何做到这一点:

(Assuming an object t) (假设一个对象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]))); }

This is also possible with Swift: 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]))]))
}

Output: 输出:

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>

Tested with the 6s simulator running iOS 9.2, Xcode Version 7.2 (7C68). 使用运行iOS 9.2,Xcode版本7.2(7C68)的6s模拟器进行测试。

Something like this should work (just put it in the object you're curious about). 这样的东西应该工作(只需将它放在你很好奇的对象中)。 For example if you have an object that's a delegate and want to know what 'hooks' are available this will print out messages to give you that clue: 例如,如果你有一个委托的对象,并想知道什么是'钩子'可用,这将打印出消息,为你提供线索:

-(BOOL) respondsToSelector:(SEL)aSelector {
    printf("Selector: %s\n", [NSStringFromSelector(aSelector) UTF8String]);
    return [super respondsToSelector:aSelector];
}

Note that I discovered this in the iPhone Developer's Cookbook so I can't take credit! 请注意,我在iPhone Developer's Cookbook中发现了这一点,所以我不能相信! For example output I get from a UIViewController that implements the protocols <UITableViewDelegate, UITableViewDataSource> : 例如,我从一个实现协议<UITableViewDelegate, UITableViewDataSource>UIViewController获得输出:

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.

Taking inspiration from JAL 's answer, in Swift you can do: JAL的答案中获取灵感,在Swift中你可以做到:

extension NSObject {
    var __methods: [Selector] {
        var methodCount: UInt32 = 0
        guard
            let methodList = class_copyMethodList(type(of: self), &methodCount),
            methodCount != 0
        else { return [] }
        return (0 ..< Int(methodCount))
            .flatMap({ method_getName(methodList[$0]) })
    }
}

ARC realization ARC实现

SomeClass *someClass = [[SomeClass alloc] init];    

//List of all methods
unsigned int amountMethod = 0;
Method *methods = class_copyMethodList(someClass, &amountMethod);

for (unsigned int i = 0; i < amountMethod; i++) {
    Method method = methods[i];

    printf("\t method named:'%s' \n", sel_getName(method_getName(method)));
}

free(methods);

If you want to also get the selectors for the super classes you can loop through like this:如果您还想获得超类的选择器,您可以像这样循环:

    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];
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM