#typedef and KVC in ObjC
Asked Answered
B

4

6

I have a class that looks like this:

@interface Properties : NSObject {
@private
    NSNumber* prop1;
    NSNumberBool* prop2;
    //etc

where NSNumberBool is a typedef:

// in MyApp_Prefix.pch
typedef NSNumber NSNumberBool;

I have all the required @property and @synthesize declarations to make prop1 and prop2 properties.

Everything compiled and worked fine until I tried to access prop2 by [myProperties valueForKey:@"prop2"]. This gives me a "class is not key-value compliant" error. However, many similar calls work fine:

myProperties.prop2; //works
[myProperties prop2]; //works
[myProperties valueForKey:@"prop1"]; //works
[myProperties valueForKey:@"prop2"] // throws NSUnknownKeyException ??

What is going on here, and how can I fix it?

Thanks,

Binky answered 16/10, 2009 at 7:9 Comment(1)
Really weird, running into the same issue myself. Also if you do [myProperties respondsToSelector:@selector(prop2)] it returns YES as wellCleary
C
2

This is pretty an old post, but I came to it while looking for a solution to this problem, which is nicely solved by Objective-C 2.0 @compatibility_alias directive. This allows you to write:

@compatibility_alias NSNumberBool NSNumber;

and have an alias created for NSNumber. KVO works perfectly with it.

Over the currently accepted answer, this has the great benefit of being type-safe.

Charmain answered 25/7, 2016 at 10:26 Comment(0)
I
4

From compiling your example and issuing class-dump on it, it appears the typedef is getting turned into

struct NSNumber {
    Class _field1;
};

@interface Properties : NSObject
{
    NSNumber *prop1;
    struct NSNumber *prop2;
}

Changing the typedef to this seems to work fine, though maybe not exactly what you want.

#define NSNumberBool NSNumber
Iterative answered 16/10, 2009 at 7:32 Comment(0)
I
4

I suspect this is an issue with the way typedef interacts with the encode method.

I believe that typedef remains a pure C keyword and really only happens to work with Objective-C "types" usually because they happen to be implemented as structs.

As a result when you typedef NSNumber to NSNumberBool it works fine for method calls (and dot syntax properties) but (assuming my theory is correct), breaks encode which can't tell that NSNumberBool and NSNumber are the same type.

I'll be interested to see what someone who knows better says.

Iraq answered 16/10, 2009 at 7:36 Comment(0)
C
2

This is pretty an old post, but I came to it while looking for a solution to this problem, which is nicely solved by Objective-C 2.0 @compatibility_alias directive. This allows you to write:

@compatibility_alias NSNumberBool NSNumber;

and have an alias created for NSNumber. KVO works perfectly with it.

Over the currently accepted answer, this has the great benefit of being type-safe.

Charmain answered 25/7, 2016 at 10:26 Comment(0)
O
1

Similar to nall's answer, I also tried class-dump. I did find an interesting, if ugly workaround. The following code:

typedef NSNumber* NSNumberBoolPtr;

@interface Test : NSObject {
    NSNumber *real;
    NSNumberBoolPtr poser;
}

class-dumps to:

@interface Test : NSObject
{
    NSNumber *real;
    NSNumber *poser;
}

@end

Again, not exactly what you want but you would get the compiler time checking of not having NSNumbers and NSNumberBools intermingling (which is I assume the reason for the typedef in the first place).

Outermost answered 16/11, 2009 at 19:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.