Как узнать о 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:
#keyPath
директива, которая также использует среду выполнения ObjC, но проверяет путь к ключу во время компиляцииlet keyPath = #keyPath(Student.name) student1.setValue("Benny", forKeyPath: keyPath)
В этом случае вы получите очень наглядное предупреждение компилятора
Аргумент "#keyPath" ссылается на свойство "name" в "Student", которое зависит от вывода "@objc", который устарел в Swift 4.
(Рекомендуемый) собственный способ: 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)")
}