将 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,但实际上并没有使用它。)
您可以使用块并将它们存储在字典中。这些块可以包含所需代码或调用包含所需代码的函数或方法。
收到 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,但实际上并没有使用它。)
您可以使用块并将它们存储在字典中。这些块可以包含所需代码或调用包含所需代码的函数或方法。