Search code examples
objective-cswift64-bit32-bitkvc

Why does setValue:forKey: fail on a 32-bit system but not 64-bit?


I recently submitted a bug report to Apple about this, but I thought I would ask the question anyways in case I'm missing something obvious. In Objective-C, the following call works fine on a 64-bit system but throws an NSInvalidArgumentException on a 32-bit system:

[self setValue:@"true" forKey:@"flag"];

The "flag" property is a BOOL:

@property BOOL flag;

Further, the call works fine in Swift/32-bit, where the property is a Bool:

var flag: Bool = false

Similarly, this call works fine in Swift on a 64-bit system but throws NSInvalidArgumentException on the 32-bit system ("index" is an Int):

setValue("2", forKey: "index")

Yet it works fine in Objective-C/32-bit, where the property is an NSInteger.

I would have expected these calls to work correctly regardless of language or processor architecture. Does anyone have any insight into why they might not?


Solution

  • The answer is there in the comments if you combine them all...

    setValue:forKey: does not require an NSNumber/NSValue for primitive-typed properties, but you would normally pass one.

    The observed issued is not down to 64-bit vs. 32-bit either, the example code can fail on 64-bit systems as well.

    It is all down to the nature of BOOL and whether it is a char or a bool,as a comment suggests - and that depends on a number of things (from Xcode 6.4 running on 10.10.5):

    /// Type to represent a boolean value.
    #if !defined(OBJC_HIDE_64) && TARGET_OS_IPHONE && __LP64__
    typedef bool BOOL;
    #else
    typedef signed char BOOL; 
    // BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
    // even if -funsigned-char is used.
    #endif
    

    setValue:forKey when setting a primitive typed property of <type> calls - <type>Value on whatever object it is passed.

    If BOOL is a char it calls - charValue, and NSString has no such method - so fail.

    If BOOL is bool it calls - boolValue, and NSString has that so all is good.

    Simple fix:

    @property bool flag;
    

    and that should work everywhere and have the added bonus that flag will always be true/false, YES/NO, 1/0 and not one of the other 254 possibilities that char can be.

    Just think how different things would be if the designers of C didn't skimp and actually included a real boolean type from the start...