【问题标题】:Add C function as value to NSDictionary将 C 函数作为值添加到 NSDictionary
【发布时间】:2017-09-07 21:13:08
【问题描述】:

收到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

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

'void (__strong id, __strong id)' 类型的集合元素不是 Objective-C 对象`

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

--

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

【问题讨论】:

    标签: ios objective-c function dictionary objective-c-blocks


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 这澄清了很多!我为我的块保留了 typedef,并将 myCommandHandler 的函数声明更改为具有定义的块声明:static const Handler myCommandHandler = ^void(id&lt;MyProtocol&gt; obj, id data) { ... };。有了这个,我可以将myCommandHandler 存储在 NSDictionary 中。这似乎比将 C 函数调用包装在无用的块对象中更干净。再次感谢
    【解决方案2】:

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

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

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

    HTH

    【讨论】:

    • 您也可以将 C 函数包装在一个块中并将该块存储在字典中。这可能会更容易。
    • 为了完整起见,您也可以使用(正确配置的)NSMapTable,但对于大多数开发人员来说,NSValue 或块可能更好。
    • 我立即尝试使用NSValue 包装我的函数指针,结果在调用它的成员pointerValue 时导致地址异常。另一个发布的答案似乎是一个更自然的解决方案,所以我改为使用它
    猜你喜欢
    • 1970-01-01
    • 2021-03-12
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多