Store selector as value in an NSDictionary
Is there a way to store a se开发者_开发百科lector in an NSDictionary
, without storing it as an NSString
?
SEL
is just a pointer, which you could store in an NSValue
:
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSValue valueWithPointer:@selector(foo)], @"foo",
nil];
To get the selector back, you can use:
SEL aSel = [[dict objectForKey:@"foo"] pointerValue];
An alternative to Georg's solution would be to convert the selector into an NSString before storing it the NSDictionary:
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
NSStringFromSelector(@selector(foo)), @"foo",
nil];
SEL selector = NSSelectorFromString([dict objectForKey:@"foo"]);
This technique, though uses more memory, gives you the ability to serialize the entire NSDictionary as a string via libraries like JSONKit.
An NSDictionary
is really just a CFDictionary
that retains and releases all keys and values. If you create a CFDictionary
directly, you can set it up to not retain and release values. You can typecast a CFDictionaryRef
to an NSDictionary *
and vice versa.
In case of using UILocalNotification
the only way is to use NSSelectorFromString([dict objectForKey:@"foo"])
. With valueWithPointer
the app crashing when setting userInfo property of UILocalNotification
object. Be careful.
While Georg's answer should work, NSValue
does also support encoding any value using an Objective-C type encoding string, which has a special way of representing SEL
— with a ":"
(as opposed to the "^v"
produced by -valueWithPointer:
, which translates into void *
).
source: Objective-C Runtime Programming Guide - Type Encodings
Working off of Georg's solution, the best API-compliant way to put a SEL
into an NSValue
into an NSDictionary
would be:
// store
NSDictionary *dict = @{
@"foo": [NSValue value:&@selector(foo) withObjCType:@encode(SEL)]
};
// retrieve
SEL aSel;
[dict[@"foo"] getValue:&aSel];
The rationale for handling a SEL
as its own beast is that the docs describe it as “an opaque type”— which means that its internal workings (even what it's typedef
d to) are off-limits to app programmers; Apple may mix it up at any time in the future.
Also, using void *
s to force the system to do what you want it to do was useful in C back in the '90s, when most of us didn't know any better. You're better than that now.
The above approach should only be used if the retrieval of the SEL
happens during the program's running duration— you shouldn't be storing that NSDictionary
to disk. If you do need to store SEL
s long-term (across app launches), you should follow David H's approach and convert it to an NSString
.
精彩评论