【问题标题】:How to build a NSArray (or NSMutableArray) of class methods in Objective-C?如何在 Objective-C 中构建类方法的 NSArray(或 NSMutableArray)?
【发布时间】:2009-02-22 15:21:12
【问题描述】:

我正在尝试在 Objective-C 中构建一个 NSArray 方法。

(我在这里尝试完成的内容类似于 C 中的以下内容)

typedef (void)(*handler)(int command);

void handleCommandA(void) { ... }
void handleCommandB(void) { ... }

static const handler handler_table[10] = {
    handleCommandA, handleCommandB, handleCommandC
};

我必须将它移植到 Objective-C,但我不知道如何 构建一个函数指针数组(在 Objective-c 世界中, 类方法)在编译时。

在 Objective-C 中,我有以下内容。

- (void)handleCommandA { ... }
- (void)handleCommandB { ... }

/* Now how to add above 2 functions into NSArray? */
NSArray *handler_table = [NSArray arrayWithObjects:... ];  /* This doesn't seem to work. */

【问题讨论】:

    标签: objective-c


    【解决方案1】:

    这里的问题是,要绑定这些函数,您必须使用返回 SEL 类型的选择器关键字。这是一个指针类型,而 NSArray 存储对象。

    因此你有三个选择;

    1. 使用常规 C 类型数组
    2. 将函数折叠到将调用它们的 NSObject 派生类中。
    3. 使用协议。

    第二个可能更好,为此您可以使用 NSValue 类来保存选择器结果。例如;

    NSValue* selCommandA = [NSValue valueWithPointer:@selector(handleCommandA:)];
    NSValue* selCommandB = [NSValue valueWithPointer:@selector(handleCommandB:)];
    
    NSArray *handler_table = [NSArray arrayWithObjects:selCommandA, selCommandB, nil ];
    

    当您从数组中检索到正确的条目后,您可以进行转换;

    SEL mySelector = [selCommand pointerValue];
    [someObject performSelector:mySelector];
    

    (请注意,我假设从您的 Objective-C 语法中,这些旨在用作对象上的方法而不是全局函数。如果您希望在全局范围内使用它们,那么您应该像平常一样编写它们C.)

    另一种选择是将命令方法形式化为协议。这允许您编写适用于任何实现该协议的对象的功能,并且编译器将提供比您仅调用选择器时更多的检查。

    例如

    // some header
    @protocol CommandHandler
    @required
    -(void) handleCommandA;
    -(void) handleCommandB;
    @end
    
    // some other header
    @interface someClass : NSObject<CommandHandler>
    {
    // you will receive compiler warnings if you do not implement the protocol functions
    }
    

    然后编写您的处理和调度代码以使用“CommandHandler”类型的对象。例如

    -(void) registerForCommands:(CommandHandler*)handler
    

    【讨论】:

    • 我更喜欢使用字符串而不是指针,因为它会使调试更容易。看看 NSStringFromSelector() 和 NSSelectorFromString()。
    • 小修正,使用选择器其实长这样:[someObject performSelector:mySelector];
    【解决方案2】:

    使用 NSValue。

    例如:

    NSArray* handlers = [NSArray arrayWithObjects:[NSValue valueWithPointer:handleA] ... ];
    

    然后访问:

    handleptr* handle = (handlerptr*)[[handlers objectAtIndex:0] pointerValue];
    handle(foo_bar);
    

    【讨论】:

      【解决方案3】:

      在 Objective-C 中,你不能传递方法;你传递选择器,它们基​​本上是方法的规范名称。然后,为了让对象响应选择器消息,您发送它performSelector:。例如:

      NSString *exampleString = [NSString stringWithString:@"Hello"];
      SEL methodName = @selector(stringByAppendingString:);
        // ^This is the selector. Note that it just represents the name of a
        //  message, and doesn't specify any class or implementation
      NSString *combinedString = [exampleString performSelector:methodName withObject:@" world!"];
      

      您需要创建一个包含您感兴趣的选择器名称的 NSString 数组。您可以使用函数NSStringFromSelector() 来执行此操作。然后,当您想使用它们时,在字符串上调用NSSelectorFromString() 以获取原始选择器并将其传递给相应对象的performSelector:。 (如上例所示,接收器未编码在选择器中——只是方法名称——因此您可能还需要存储接收器。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-29
        • 1970-01-01
        • 2015-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-14
        • 1970-01-01
        相关资源
        最近更新 更多