Как узнать о KVC с помощью Swift 4.2

Я использую Xcode 10.0 с swift 4.2, чтобы узнать о Key Value Coding из "Какао программирования для OSX"

Меня просят создать простой класс, который является подклассом NSObject. Коды ниже:

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")

Создает следующее сообщение об ошибке:

Выполнение было прервано, причина: EXC_BAD_INSTRUCTION (код =EXC_I386_INVOP, субкод =0x0).

Я посмотрел в Интернете и, кажется, некоторые проблемы, касающиеся KVC, такие как: https://bugs.swift.org/browse/SR-5139

Что я делаю неправильно? Книга была издана в 2015 году.

2 ответа

Решение

В Swift 4 предоставление кода среде выполнения Objective C больше не выводится из соображений производительности.
Чтобы избежать аварии, вы должны добавить @objc атрибут явно.

@objc var name: String = ""

Но с точки зрения сильного типа Swift есть два лучших способа получить значения с помощью KVC:

  1. #keyPath директива, которая также использует среду выполнения ObjC, но проверяет путь к ключу во время компиляции

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

    В этом случае вы получите очень наглядное предупреждение компилятора

    Аргумент "#keyPath" ссылается на свойство "name" в "Student", которое зависит от вывода "@objc", который устарел в Swift 4.

  2. (Рекомендуемый) собственный способ: Swift 4+ предоставляет свой собственный шаблон KVC, в котором подклассы NSObject не требуется.
    Ключевые пути обозначаются начальным обратным слешем, за которым следуют тип и свойство (или свойства):

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

Простой пример KVC

Здесь мы получаем доступ к свойству имени SimpleClass напрямую через экземпляр.

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

   }
 }

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

Но в KVC здесь мы получаем доступ к свойству name класса через 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)")
}
Другие вопросы по тегам