-3

I found that using KVC in Swift causes many problems, especially with optional properties.

Here is my specific problem:

Here is a Class named Person. It has a normal property called age,and a Optional(Int) property called ageOptional.

class Person: NSObject {

    var age: Int

    var ageOptional: Int?


    override init(age: Int){

        self.age = 0
    }
}

Now, I use KVC in Person's instance:

//new a instance
var person = Person()

//kvc for normal property: it work well
person.setValue(28, forKeyPath: "age")


//but, this time ,it doesn't work well!!!!
person.setValue(28, forKeyPath: "ageOptional")

The app crashes, and here is the exception:

2015-07-11 11:17:31.546 CFRuntime[4646:607] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key ageOptional.'

I found that, if a property is optional, KVC couldn't find the key. But,I can't find the useful key for an optional property ,and resolve this situation.

Pang
  • 9,564
  • 146
  • 81
  • 122
charlin
  • 5
  • 1
  • 2
    Remove the Chinese chars, it's really not necessary, English is what people use here. And there is really no need for the multiple `!` characters. Clear & well-formated questions would get answers. – Eric Jul 11 '15 at 03:26
  • [ setValue:forUndefinedKey:] – charlin Jul 11 '15 at 03:27

1 Answers1

2

You have already solved the problem perfectly. You cannot use KVC on an Optional Int property, because KVC is Cocoa / Objective-C, and Objective-C cannot see an Optional Int - it is not bridged to Objective-C. Objective-C can only see types that are bridged to Objective-C:

  • class types that are derived from NSObject

  • class types that are exposed with @objc

  • Swift structs that are bridged

Objective-C can also see an Optional wrapping any of those types - almost. It can see an Optional wrapping a bridged struct, but only if that struct is directly bridged. Int is not directly bridged; it is bridged to NSNumber, but not directly (it has to be wrapped). Thus, Objective-C cannot see a Swift member typed as an Int?.

If you really need this to be an Optional, and if you really need to use KVC on it, then declare it as NSNumber?, not Int?. Personally, I would doubt whether either of those things is true; since converting all my apps from Objective-C to Swift, I've found that I don't actually need KVC internally, and that all my KVC-based solutions can be done some other, better way.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Oh No, But, I test a String Optional Property and Use KVC again, it's work well....... class Person: NSObject { var name: String? } then – charlin Jul 11 '15 at 03:44
  • Oh No, But, I test a String Optional Property and Use KVC again, it's work well....... var name: String? var person = Person() person.setValue("张三", forKeyPath: "name") – charlin Jul 11 '15 at 03:46
  • But not `Int?`. If you really need this to be an Optional, use `NSNumber?`. – matt Jul 11 '15 at 03:46
  • you can override [setValue:forUndefinedKey:] and handle the optional support yourself. – RK1979 Dec 03 '15 at 04:33
  • you can also add `@objc` to your properties that are not recognized and it will bridge to objective c – Charlton Provatas Mar 31 '18 at 21:23