It seems that only a specific subset of primitive types is supported for automatic boxing / unpacking by default setValue:forKey: See Table 1 and Table 2 in the "Scalar and Structural Support" chapter of the "Key Code Programming Guide " chapter . It is understood here that only BOOL , char , double , float , int , long , long long , short and their unsigned copies are fully supported along with struct via NSValue . Other types, such as SEL and other pointer values, are unsupported .
Consider the following program:
We can easily set the int and id properties - even using __unsafe_unretained and bridge translations so that we can pass the value of the selector. However, trying to set either of the two types of pointers is not supported.
How do we get out of here? For example, we could override valueForKey: and setValueForKey: in MyObject to support decompression of SEL types or to intercept a specific key. An example of the latter approach:
@implementation MyObject - (id)valueForKey:(NSString *)key { if ([key isEqualToString:@"mySelector"]) { return [NSValue valueWithPointer:self.mySelector]; } return [super valueForKey:key]; } - (void)setValue:(id)value forKey:(NSString *)key { if ([key isEqualToString:@"mySelector"]) { SEL toSet; [(NSValue *)value getValue:&toSet]; self.mySelector = toSet; } else { [super setValue:value forUndefinedKey:key]; } } @end
When used, we find that it works as expected:
[object setValue:selectorValue forKey:@"mySelector"]; NSString *string = NSStringFromSelector(object.mySelector); NSLog(@"selector string = %@", string);
This log displays "selector string = description" on the console.
Of course, this is due to maintainability, since now you need to implement these methods in each class, you need to install selectors with KVC, and you will also have to compare it with hard-coded keys. One way that is risky is to use the swizzling method and replace the replacement of NSObject implementation of the KVC methods of our own, which handle the boxing and unpacking of SEL types.
The following program, built on the first example, is very different from Mike Ash's brilliant let build KVC , and also uses the Swizzle() function from this answer to SO . Note that I cut corners for the purpose of demonstration, and that this code will only work with SEL attributes that have getters and setters named accordingly, and will not directly check instance variables, unlike the default KVC implementations.
The result of this program demonstrates the capabilities of boxing and unboxing:
2013-08-30 19:37:14.287 KVCSelector[69452:303] fromProperty = description fromKVC = description 2013-08-30 19:37:14.288 KVCSelector[69452:303] int from kvc = 1 from propety = 1 2013-08-30 19:37:14.289 KVCSelector[69452:303] after setting the selector with KVC: class 2013-08-30 19:37:14.289 KVCSelector[69452:303] after setting the int with KVC: 42
Swizzling, of course, is not without risk, so proceed with caution!