将选择器作为值存储在 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
当作自己的野兽来处理的基本原理是文档将其描述为“不透明的类型”——这意味着它的内部工作方式(甚至是 typedef
d 的内部工作方式)是应用程序的禁区程序员; Apple 可能会在未来的任何时候将其混为一谈。
此外,使用void *
s 来强制系统执行您希望它执行的操作在 90 年代的 C 语言中很有用,当时我们大多数人对此一无所知。 你现在比那更好了。
只有在程序运行期间检索SEL
时才应使用上述方法——您不应该将NSDictionary
存储到磁盘。如果您确实需要长期存储SEL
s(跨应用启动),您应该关注David H's approach 并将其转换为NSString
。
【讨论】:
以上是关于将选择器作为值存储在 NSDictionary 中的主要内容,如果未能解决你的问题,请参考以下文章
“-[__NSDictionaryI 长度]:无法识别的选择器发送到实例”没有 NSDictionary 的错误?
如何将传入的结果作为 id 存储到 NSDictionary
只有 NSDictionary 中的属性列表对象(NSNumber),但不能在 UserDefaults 中存储 dict