Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using setValue(value, forKey: key) on Int? types fires non key value coding-compliant method

I'm successfully using the setValue(value, forKey: key) method in my NSKeyValueCoding compliant Swift NSObject subclass.

This works perfectly well on String optionals, e.g.

var name:String?

However, on Int optionals, it fails, triggering the undefined key method that I have overridden for debugging purposes:

override func setValue(value: AnyObject!, forUndefinedKey key: String!) {
    println("\(self) this class is not key value coding-compliant for the key \(key)")
}

So for example, a key of myId with a good integer value would trigger the undefined key method above.

var myId:Int?

If I change the above definition to be non-optional, then everything works fine:

var myId:Int = 0

With myId as an optional, I have tried absolutely everything I can think of in the way of casting, unwrapping, initialising, and so on. It just doesn't see the class as key value compliant for those numeric values.

I know that it is a good numeric value. Changing the var declaration to String? crashes. It also looks fine in lldb:

Printing description of key:
myId
key NSObject    0x00007fb8d530ca20  0x00007fb8d530ca20
k   NSString    "myId"  0x00007fa2aa942f20
value   __NSCFNumber *  Int64(4348129)  0xb000000004258e13
Printing description of value:
4348129
(lldb) 

So, the question is, has anyone used - in Swift - the NSKeyValueCoding method setValue(value, forKey: key) on an Int type successfully?

like image 817
Max MacLeod Avatar asked Sep 30 '14 10:09

Max MacLeod


2 Answers

KVO cannot function with pure Swift optionals because pure Swift optionals are not Objective-C objects. Swift forbids the use of dynamic or @objc with generic classes and structures because there is no valid Objective-C equivalent, and so the runtime is not setup to support KVO on instances of those kinds of objects. As for why it works with String?, that type is toll-free bridged to NSString, so it is semantically equivalent to NSString *, an Objective-C type that the runtime knows full-well how to deal with. But compare that to Int? whose semantic equivalent would be Optional<Int>, not UnsafePointer<Int> or NSNumber * like you might expect. For now, you'll need to convince the typechecker that it is safe to represent in Objective-C by using NSNumber!.

This is completely backwards and, in my opinion, an unfortunate limitation of the type system. For any engineers that come across this post, see rdar://18624182.

like image 78
CodaFi Avatar answered Nov 12 '22 23:11

CodaFi


If you're willing to ditch Swift types change:

var myId:Int?

to:

var myId:NSNumber?
like image 3
TenaciousJay Avatar answered Nov 12 '22 22:11

TenaciousJay