NSKeyValueCoding.setValue(_:forKey:) 在 SwiftUI 中不工作

NSKeyValueCoding.setValue(_:forKey:) not working in SwiftUI

我无法生成适当的最小工作示例,主要是由于我对 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."

我一直在查看答案 here 但由于大多数答案都涉及 xib 和故事板文件(我没有,或者不知道如何找到),我不知道看看它们之间的关系。

顺便说一句,即使我实际尝试修复的应用程序不使用 SwiftUI 并且 setValue 的问题有所不同,但我确实没有 .xib 或 .storyboard 文件或我只是不知道在哪里可以找到它们。

如果有人可以帮助我找出我的示例中的问题,或者可以让我更接近解决实际应用程序的问题(包括如何生成适当的 MWE),我将不胜感激。

我相信我已经写的内容足以解决这个问题(至少一开始是这样),但对于那些感兴趣的人,我想我会添加完整的故事。

全文

我是 iOS 开发的新手,我刚刚获得了旧 iOS 应用程序的所有权。它自 2017 年以来就没有真正被触及过。我注意到一个动画不起作用。虽然我无法验证它是否曾经工作过,但我有充分的理由假设它曾经工作过,但我不能说它何时停止工作。

我注意到的一个问题是动画属性应该使用 NSKeyValueCoding.setValue(_:forKey:) 函数更新,但调用该函数时似乎没有任何反应。

我能够通过用我自己的 setValue 函数覆盖来解决这个问题,该函数基本上使用 switch 语句将每个键映射到其对应的值。但是,这并没有修复动画或解释为什么 setValue 函数不起作用。

因为 setValue 函数和 CABasicAnimation.add(_:forKey:) 都依赖于相同的 keyPath,我想知道解决一个问题是否可以帮助我解决另一个问题。我决定专注于 setValue 问题(至少现在)。

当我开始一个新项目作为 MWE 使用时,我注意到 Xcode 13.0 (13A233) 提供的 Storyboard 和 SwiftUI 界面选项都没有启动我的项目结构匹配我现有的项目。我很清楚 SwiftUI 是新的,与我现有的项目有很大不同,但 Storyboard 界面也不熟悉,在阅读教程几分钟后,我未能构建一个能够响应按钮按下的 Storyboard 应用程序(我发现的所有情节提要应用程序教程似乎都是为 Xcode) 的旧版本设置的。

SwiftUI 将要求您使用@O​​bservedObject 来对对象的变化做出反应。您可以使它符合观察对象和键值操作,如下所示:

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 一起使用。这是必需的,因为键值 Observing/Coding 机制是一项 Objective-C 功能。

所以,要么

class MyClass: NSObject {
    @objc var txt: String = ""

,或

@objcMembers class MyClass: NSObject {
    var txt: String = ""

这将修复该错误,并应使您的应用按预期运行。但是,正如其他人所说,您需要对代码进行更多更改才能遵守 SwiftUI 范例。