1

The code in the minimal example (so minimal it does not really make sense...) below crashes: *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__lldb_expr_345.People 0x60800002a5a0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key names.'

It works just fine if the dictionary is change from [String, LastName?] to [String, LastName]. So I guess the type Optional<LastName> is not representable using KVC some how? I thought it would be able to infer the type to _Nullable.

How can I make this code work with a dictionary containing Optional values (my own NSObject subclass or value types)?

class LastName: NSObject {
    let name: String
    init(_ name: String) { self.name = name }
    override var description: String { return name }
}

class People: NSObject {
    var names: [String: LastName?] = [:] //problem caused by optional `Lastname`
    override var description: String {
        return "names: \(names)"
    }
}

func createPeople(_ names: [String: LastName]) -> NSObject {
    let classType: NSObject.Type = People.self
    let instance = classType.init()
    instance.setValue(names, forKey: "names") //crash here NSUnknownKeyException
    return instance
}


print(createPeople(["Steve": LastName("Jobs")]))
Sajjon
  • 8,938
  • 5
  • 60
  • 94
  • You are combining Objective C with Swift Optionals. This isn't going to work. Using an optional in a function signature or property makes that function or property invisible to Objective C – Paulw11 Feb 21 '17 at 08:56

1 Answers1

0

In Objective-C, a dictionary cannot have a value of nil. To allow an equivalent, there is a class called NSNull which is what used to be used instead, in non-modern Objective-C.

But in the modern Objective-C/Swift world, names without the optional value would have a type like:

NSDictionary<NSString, LastName>*

The key and value types in an NSDictionary cannot be tagged as being nullable. If you tried to force the names member to be accessible in Objective-C, like:

@objc var names: [String: LastName?] = [:]

you would get a compilation error:

error: property cannot be marked @objc because its type cannot be represented in Objective-C

As a workable solution, change the type of names to:

var names: [String: Any] = [:]

and use NSNull.null as a placeholder for not having a value. Old school, but it will work.

Gary Makin
  • 3,109
  • 1
  • 19
  • 27
  • In addition, to the above. See documentation of Dictionary in API reference. https://developer.apple.com/reference/swift/dictionary It states If you assign nil to an existing key, the key and its associated value are removed. Thus I assume, this will not cause the behaviour that you intend by setting the value to optional. – Carien van Zyl Feb 21 '17 at 09:06