开发者

Store selector as value in an NSDictionary

开发者 https://www.devze.com 2022-12-30 06:25 出处:网络
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:

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 typedefd 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 SELs long-term (across app launches), you should follow David H's approach and convert it to an NSString.

0

精彩评论

暂无评论...
验证码 换一张
取 消