Daniel Hall
Daniel Hall

Reputation: 854

How to learn about KVC with swift 4.2

I'm using Xcode 10.0 with swift 4.2 to learn about Key Value Coding from "Cocoa programming for OSX"

I'm asked to create a simple class, which is a subclass of NSObject. The codes below:

import Cocoa

class Student: NSObject {
    var name: String = ""
    var gradeLevel: Int = 0
}

let student1 = Student()


student1.setValue("Benny", forKeyPath: "name")

student1.setValue("Benny", forKeyPath: "name")

Generates the following error message:

Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).

I've looked online and seem some issues regarding KVC such as : https://bugs.swift.org/browse/SR-5139

What am I doing wrong? The book was published in 2015.

Upvotes: 6

Views: 4544

Answers (2)

MannaICT13
MannaICT13

Reputation: 309

Simple Example of KVC

Here we access the name property of SimpleClass directly through the instance.

class SimpleClass {
var name: String
init(name: String) {
    self.name = name

   }
 }

let instance = SimpleClass(name: "Mike")
let name = instance.name
print("name: \(name)")

But in KVC Here we access the name property of the class through forKey.

class KVCClass: NSObject {
    @objc dynamic var name: String
    init(name: String) {
        self.name = name
    }
}

let instance = KVCClass(name: "Mike")
if let name = instance.value(forKey: "name") as? String {
    print("name: \(name)")
}

Upvotes: 1

vadian
vadian

Reputation: 285150

In Swift 4 exposing code to the Objective-C runtime is no longer inferred for performance reasons.
To avoid the crash you have to add the @objc attribute explicitly.

@objc var name: String = ""

But from the strong type perspective of Swift there are two better ways to get values with KVC:

  1. The #keyPath directive which uses the ObjC runtime, too, but checks the key path at compile time

    let keyPath = #keyPath(Student.name)
    student1.setValue("Benny", forKeyPath: keyPath)
    

    In this case you get a very descriptive compiler warning

    Argument of '#keyPath' refers to property 'name' in 'Student' that depends on '@objc' inference deprecated in Swift 4

  2. The (recommended) native way: Swift 4+ provides its own KVC pattern where subclassing NSObject is not required.
    Key paths are indicated by a leading backslash followed by the type and the property (or properties):

    class Student {
        var name: String = ""
        var gradeLevel: Int = 0
    }
    
    let student1 = Student()
    student1[keyPath: \Student.name] = "Benny"
    

Upvotes: 12

Related Questions