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.

Другие вопросы по тегам