How to learn about KVC with swift 4.2
Asked Answered
A

2

6

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.

Ardellardella answered 3/10, 2018 at 20:36 Comment(3)
Did you read the full bug report? "Swift 4 no longer exposes properties to Objective-C by default unless they're overriding something or satisfying a protocol requirement. Use the objc attribute to expose them explicitly. You can read more about this in the Xcode 9 release notes."Rachael
Hi, Thanks for the reply. Yes I did read the full report, and thought of reading the Xcode 9 release notes. The report was from 2017. I just didn't want to go down the wrong rabbit hole chasing things and though it best to ask.Ardellardella
See Key-path Expression in the Swift book.Condone
R
12

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"
    
Roulette answered 3/10, 2018 at 20:45 Comment(6)
This is really interesting and a perfect answer.... i will take @Martin_R suggestion to and read XC9 release notes... soon ! thanksArdellardella
There must be another way to do this that falls in with swift. The syntax doesn't look right the back slash is out of place and uneededArdellardella
Please watch WWDC 2017 : What's new in Foundation from 4:30Roulette
OK here is 57 minutes of my life ;)Ardellardella
There are worse ways to waste life time 😉 Watch the video and you will understand the syntaxRoulette
21 minutes in and the I'm listening about KVO which I really wanted to ask but thought I'd get the "Off topic" beat down. Thanks man :) really good video. I wish I got 30% of what they are talking about but will watch again in 1 month. Do you have a link to more ?Ardellardella
M
1

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)")
}
Maramarabel answered 3/11, 2022 at 9:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.