NSKeyValueCoding.setValue(_:forKey:) не работает
Я не могу создать правильный минимальный рабочий пример, в основном из-за моего понимания разработки iOS на уровне новичка, но у меня есть простой проект SwiftUI, который может помочь.
В моем ContentView.swift:
import SwiftUI
struct ContentView: View {
@State var viewText :String
var myClass :MyClass
var body: some View {
VStack{
Text(viewText)
.padding()
Button("Update Text", action: {
myClass.update()
viewText = myClass.txt
})
}
}
}
class MyClass: NSObject {
var txt :String = ""
var useSetVal :Bool = false
func update(){
if(useSetVal){
setValue("used set val", forKey: "txt")
} else {
txt = "used ="
}
useSetVal = !useSetVal
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let mc = MyClass()
ContentView(viewText: "", myClass: mc)
}
}
и в моем PracticeApp.swift
import SwiftUI
@main
struct PracticeApp: App {
var body: some Scene {
WindowGroup {
let mc = MyClass()
ContentView(viewText: "", myClass: mc)
}
}
}
В этом приложении я ожидаю увидеть текстовое переключение между «used =» и «used setVal» при нажатии кнопки. Вместо этого я получаю исключение, когда вызываю setValue:
Thread 1: "[<Practice.MyClass 0x60000259dc20> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key txt."
Я просматривал ответы здесь, но поскольку большинство ответов относятся к файлам xib и раскадровки (которых у меня либо нет, либо я не знаю, как их найти), я не понимаю, как они связаны.
Кстати, хотя приложение, которое я на самом деле пытаюсь исправить, не использует SwiftUI и проблема с setValue другая, все же верно, что у меня либо нет файлов .xib или .storyboard, либо их просто нет. знаю, где их найти.
Я был бы признателен за помощь от любого, кто мог бы помочь мне разобраться в проблеме с моим примером, или кто может приблизить меня к решению проблемы с моим фактическим приложением (включая то, как создать надлежащий MWE).
Я считаю, что того, что я уже написал, достаточно для проблемы (по крайней мере, для начала), но для тех, кто заинтересован, я подумал, что добавлю полную историю.
Полная история
Я новичок в разработке iOS и только что стал владельцем старого приложения для iOS. Его особо не трогали с 2017 года. Я заметил, что анимация не работает. Хотя я не могу проверить, действительно ли он работал, у меня есть веские основания предполагать, что когда-то он работал, но я не могу сказать, когда он перестал работать.Я заметил одну проблему: предполагается, что анимированные свойства обновляются функцией NSKeyValueCoding.setValue(_:forKey:), но при вызове функции ничего не происходит.
Мне удалось обойти эту проблему, заменив функцию setValue своей собственной, которая в основном использует оператор switch для сопоставления каждого ключа с соответствующим значением. Однако это не исправило анимацию и не объяснило, почему функция setValue не работает.
Поскольку и функция setValue, и CABasicAnimation.add(_:forKey:) полагаются на один и тот же keyPath, мне интересно, может ли решение одной проблемы помочь мне решить другую. Я решил сосредоточиться на проблеме setValue (по крайней мере, пока).
Когда я приступил к работе, начиная новый проект для использования в качестве MWE, я заметил, что ни Storyboard, ни параметры интерфейса SwiftUI, предоставляемые Xcode 13.0 (13A233), не запускали меня со структурой проекта, которая соответствовала моему существующему проекту. Мне было ясно, что SwiftUI был новым и сильно отличался от моего существующего проекта, но интерфейс раскадровки тоже был незнаком, и после нескольких минут чтения руководств я не смог создать приложение раскадровки, которое вообще реагировало бы на нажатия кнопок ( все учебные пособия по раскадровке, которые я нашел, похоже, были настроены для более старых версий Xcode).
2 ответа
SwiftUI потребует, чтобы вы использовали @ObservedObject, чтобы реагировать на изменения в объекте. Вы можете сделать это совместимым как с наблюдаемым объектом, так и с манипуляциями с ключом следующим образом:
struct ContentView: View {
@State var viewText :String
@ObservedObject var myClass :MyClass
var body: some View {
VStack{
Text(viewText)
.padding()
Button("Update Text", action: {
myClass.update()
viewText = myClass.txt
})
}
}
}
class MyClass: NSObject, ObservableObject {
@objc dynamic var txt: String = ""
@Published var useSetVal: Bool = false
func update(){
if(useSetVal){
setValue("used set val", forKey: "txt")
} else {
txt = "used ="
}
useSetVal = !useSetVal
}
}
Вам нужно сделать
txt
свойство, доступное для Objective-C, чтобы заставить его работать с KVO / KVC. Это необходимо, поскольку механизм наблюдения / кодирования значений ключа является функцией Objective-C.
Так что либо
class MyClass: NSObject {
@objc var txt: String = ""
, или
@objcMembers class MyClass: NSObject {
var txt: String = ""
Это исправит ошибку и заставит ваше приложение вести себя должным образом. Однако, как говорили другие, вам нужно внести больше изменений в код, чтобы придерживаться парадигм SwiftUI.