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

Posted

技术标签:

【中文标题】NSKeyValueCoding.setValue(_:forKey:) 在 SwiftUI 中不起作用【英文标题】:NSKeyValueCoding.setValue(_:forKey:) not working in SwiftUI 【发布时间】:2021-10-14 21:40:44 【问题描述】:

我无法生成一个合适的最小工作示例,主要是由于我对 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 设置的)。

【问题讨论】:

【参考方案1】:

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
    

【讨论】:

你是对的。做到了。在这里,我将 Text 视图绑定到我的 viewText 字符串而不是直接绑定到 myClass.txt 的全部原因是 MyClass 不需要是 ObservableObject。显然,只要您只直接设置值(而不是键值编码)就可以了。知道为什么会这样吗? 经过实验,我发现它实际上与作为 ObservableObject 无关。只需将 txt 变量标记为 @objc dynamic【参考方案2】:

您需要使 txt 属性对 Objective-C 可用,以使其与 KVO/KVC 一起使用。这是必需的,因为键值观察/编码机制是 Objective-C 的特性。

所以,要么

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

,或

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

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

【讨论】:

以上是关于NSKeyValueCoding.setValue(_:forKey:) 在 SwiftUI 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章