将选择器作为值存储在 NSDictionary 中

Posted

技术标签:

【中文标题】将选择器作为值存储在 NSDictionary 中【英文标题】:Store selector as value in an NSDictionary 【发布时间】:2011-02-18 20:07:58 【问题描述】:

有没有办法将选择器存储在NSDictionary 中,而不是将其存储为NSString

【问题讨论】:

【参考方案1】:

SEL 只是一个指针,您可以将其存储在NSValue 中:

NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: 
                       [NSValue valueWithPointer:@selector(foo)], @"foo",
                       nil];

要取回选择器,您可以使用:

SEL aSel = [[dict objectForKey:@"foo"] pointerValue];

【讨论】:

也许还提到要取回 SEL,您必须这样做:SEL *aSel = [[dict objectForKey:@"foo"] pointerValue]; 当我按照您的建议检索 SEL 并尝试 self performSelector:*aSel withObject:nil afterDelay:0.0];我得到:EXC_BAD_ACCESS。检索它们的正确方法是 SEL aSel = [[dict objectForKey:@"foo"] pointerValue]; [self performSelector:aSel withObject:nil afterDelay:0.0]; 新手问题:如何执行选择器? @JohanKarlsson:例如使用performSelector: 变体之一。不过,更多细节会更适合新问题。 @GeorgFritzsche 恕我直言,如果您仅添加一行作为有关如何使用 SEL 的示例,您的答案会更完整。没有那么多工作,但很好。只是一个建议。我同意如何以更广泛的方式使用选择器可能是一个自己的问题。【参考方案2】:

Georg 解决方案的替代方案是将选择器转换为 NSString,然后再将其存储到 NSDictionary:

NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: 
                      NSStringFromSelector(@selector(foo)), @"foo",
                      nil];

SEL selector = NSSelectorFromString([dict objectForKey:@"foo"]);

这种技术虽然使用更多内存,但让您能够通过 JSONKit 等库将整个 NSDictionary 序列化为字符串。

【讨论】:

乔治,这是我的错。我确实为用于检索它的字典键设置了一个选择器。感谢您的跟进。我会更新我的答案。 *糟糕,错字。我的意思是说:“我忘了为字典中的那个键设置一个选择器值。” 啊,这就解释了。很高兴听到你想通了。 如果您使用字符串作为选择器名称,我建议您使用[obj respondsToSelector:selector] 来防止拼写错误。【参考方案3】:

NSDictionary 实际上只是一个CFDictionary,它保留和释放所有键和值。如果您直接创建CFDictionary,您可以将其设置为不保留和释放值。您可以将CFDictionaryRef 类型转换为NSDictionary *,反之亦然。

【讨论】:

当我将 Foundation 对象作为键但将非 Foundation 对象作为值时,我会这样做。【参考方案4】:

如果使用UILocalNotification,唯一的方法是使用NSSelectorFromString([dict objectForKey:@"foo"])。使用valueWithPointer 设置UILocalNotification 对象的userInfo 属性时应用程序崩溃。小心点。

【讨论】:

【参考方案5】:

虽然Georg's answer 应该可以工作,但NSValue 也支持使用Objective-C 类型的编码字符串对任何值进行编码,它有一种表示SEL 的特殊方式——用":" (相反到-valueWithPointer:产生的"^v",翻译成void *)来源:Objective-C Runtime Programming Guide - Type Encodings

使用 Georg 的解决方案,将 SEL 放入 NSValue 放入 NSDictionary 的最佳 API 兼容方法是:

// store
NSDictionary *dict = @
    @"foo": [NSValue value:&@selector(foo) withObjCType:@encode(SEL)]
;

// retrieve
SEL aSel;
[dict[@"foo"] getValue:&aSel];


SEL 当作自己的野兽来处理的基本原理是文档将其描述为“不透明的类型”——这意味着它的内部工作方式(甚至是 typedefd 的内部工作方式)是应用程序的禁区程序员; Apple 可能会在未来的任何时候将其混为一谈。

此外,使用void *s 来强制系统执行您希望它执行的操作在 90 年代的 C 语言中很有用,当时我们大多数人对此一无所知。 你现在比那更好了。

只有在程序运行期间检索SEL 时才应使用上述方法——您不应该将NSDictionary 存储到磁盘。如果您确实需要长期存储SELs(跨应用启动),您应该关注David H's approach 并将其转换为NSString

【讨论】:

以上是关于将选择器作为值存储在 NSDictionary 中的主要内容,如果未能解决你的问题,请参考以下文章

“-[__NSDictionaryI 长度]:无法识别的选择器发送到实例”没有 NSDictionary 的错误?

如何将传入的结果作为 id 存储到 NSDictionary

只有 NSDictionary 中的属性列表对象(NSNumber),但不能在 UserDefaults 中存储 dict

在 NSDictionary 中获取值

NSDictionary:将 NSString 键转换为小写以在其上搜索字符串

发送到实例的 iOS 无法识别的选择器 - 将 NSDictionary 添加到 NSMutableArray