将 C 函数作为值添加到 NSDictionary

Add C function as value to NSDictionary

收到 NSString 后,我想调用一个特定的代码块。我认为 NSDictionary 最适合将它们关联起来。简化后,我使用的是:

MyProtocol.h:

@protocol MyProtocol <NSObject>

typedef void (^Handler)(id<MyProtocol> obj, id data);

@end

MyClass.h:

@interface MyClass : NSObject <MyProtocol>

- (void)aMethodWithString:(NSString *)string andData:(id)data;

@end

MyClass.m:

@interface MyClass ()

void myCommandHandler(id<MyProtocol> obj, id data); // matches signature defined in protocol

@end

@implementation MyClass

void myCommandHandler(id<MyProtocol> obj, id data)
{
    // ...
}

- (void)aMethodWithString:(NSString *)string andData:(id)data
{
    static NSDictionary<NSString *, Handler> *handler;
    static dispatch_once_t onceToken;

    // don't allocate this dictionary every time the function is called
    dispatch_once(&onceToken,
        ^{  
            handler =
                @{
                    @"MyCommand":myCommandHandler,
                };
        });

    // ... error checking, blah blah ...

    Handler block;
    if ((block = handler[string]))
        { block(self, data); }
}
@end

使用这个,我在字典文字构造中遇到错误:

Collection element of type 'void (__strong id<MyProtocol>, __strong id)' is not an Objective-C object`

那么如何在字典中包含 C 函数或块引用?将要定义相当多的更大的复杂函数,因此 非常 最好不要将所有函数都定义在字典文字本身中(我知道这种技术会起作用) .

--

此外,我不确定这里什么是正确的样式:(1) 我最初在文件范围内的任何方法体之外都有字典声明(没有 dispatch_once(...)),这会产生相同的错误,但我认为通过 (2) 将它包含在使用该字典的唯一方法中,其他人可能更容易看到发生了什么。出于某种原因,一种风格优于另一种风格吗?

C函数地址不是Objective-C对象,NSDictionary只能存储后者

C 函数地址只是一个指针,使用 NSValue 及其 class 方法将 C 指针包装为对象 valueWithPointer

要从 NSValue 对象中取回指针值,您可以使用实例方法 pointerValue。在使用提取的指针之前,您必须将其转换为您的函数类型。

HTH

你的Handler类型是块类型,不是函数指针类型。如果您使用 * 而不是 ^ 声明它,它将是一个函数指针类型。

您的 myCommandHandler 函数当然是函数,而不是块。你的评论是错误的。它匹配类型Handler

函数指针不是Objective-C对象指针。函数不是对象。块 Objective-C 对象,但您实际上并未在此处使用任何块。 (您刚刚为一个声明了一个 typedef,但实际上并没有使用它。)

您可以使用块并将它们存储在字典中。这些块可以包含所需代码或调用包含所需代码的函数或方法。