简体   繁体   English

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

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

I am unable to produce a proper minimal working example, mainly due to my novice level understanding of iOS development, but I do have a simple SwiftUI project that may help.我无法生成一个合适的最小工作示例,主要是由于我对 iOS 开发的新手级理解,但我确实有一个简单的 SwiftUI 项目可能会有所帮助。

In my ContentView.swift:在我的 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)
    }
}

and in my PracticeApp.swift在我的 PracticeApp.swift 中

import SwiftUI

@main
struct PracticeApp: App {
    var body: some Scene {
        WindowGroup {
            let mc = MyClass()
            ContentView(viewText: "", myClass: mc)
        }
    }
}

In this app, I expect to see the text toggle between "used =" and "used setVal" as I push the button.在这个应用程序中,当我按下按钮时,我希望看到“used =”和“used setVal”之间的文本切换。 Instead, I get an exception when I call setValue:相反,当我调用 setValue 时出现异常:

Thread 1: "[<Practice.MyClass 0x60000259dc20> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key txt."

I've been reviewing the answers here but since most answers refer to xib and storyboard files (which I either don't have, or don't know how to find), I don't see how they relate.我一直在查看这里的答案但由于大多数答案都涉及 xib 和故事板文件(我要么没有,要么不知道如何找到),所以我看不出它们之间的关系。

By the way, even though the app I'm actually trying to fix doesn't use SwiftUI and the issue with setValue is different, it's still true that I either don't have .xib or .storyboard files or I just don't know where to find them.顺便说一句,即使我实际尝试修复的应用程序不使用 SwiftUI 并且 setValue 的问题是不同的,但我仍然没有 .xib 或 .storyboard 文件,或者我只是没有知道在哪里可以找到它们。

I'd appreciate help from any one who could either help me figure out the issue with my example, or who can get me closer to solving the issue with my actual app (including how to produce a proper MWE).我很感激任何人的帮助,他们可以帮助我通过我的示例解决问题,或者可以让我更接近使用我的实际应用程序解决问题(包括如何生成适当的 MWE)。

I believe what I've already written is sufficient for the issue (at least for a start), but for those interested, I thought I'd add the full story.我相信我已经写的内容足以解决这个问题(至少在开始时),但对于那些感兴趣的人,我想我会添加完整的故事。

The Full Story完整的故事

I'm new to iOS development, and I've just taken ownership of an old iOS app. 我是 iOS 开发的新手,我刚刚拥有了一个旧的 iOS 应用程序。 It hasn't really been touched since 2017. I noticed an animation that is not working. 自 2017 年以来就没有真正接触过它。我注意到一个动画不起作用。 Though I cannot verify that it ever did work, I have good reason to assume that it once did, but I can't say when it stopped working. 虽然我无法验证它是否确实有效,但我有充分的理由假设它曾经有效,但我不能说它何时停止工作。

One issue I noticed is that animated properties are supposed to be updated with the NSKeyValueCoding.setValue(_:forKey:) function, but nothing seems to happen when the function is called.我注意到的一个问题是动画属性应该使用 NSKeyValueCoding.setValue(_:forKey:) 函数进行更新,但在调用该函数时似乎没有任何反应。

I was able to work around the issue by overriding the setValue function with my own which basically uses a switch statement to map each key to its corresponding value.我能够通过用我自己的覆盖 setValue 函数来解决这个问题,该函数基本上使用 switch 语句将每个键映射到其相应的值。 However, this did not fix the animation or explain why the setValue function isn't working.但是,这并没有修复动画或解释 setValue 函数不起作用的原因。

Because both the setValue function and the CABasicAnimation.add(_:forKey:) rely on the same keyPath, I wonder if solving one issue might help me solve the other.因为 setValue 函数和 CABasicAnimation.add(_:forKey:) 都依赖于相同的 keyPath,所以我想知道解决一个问题是否可以帮助我解决另一个问题。 I've decided to focus on the setValue issue (at least for now).我决定关注 setValue 问题(至少现在是这样)。

When I went to work starting a new project to use as an MWE, I noticed that neither the Storyboard nor the SwiftUI interface options provided by Xcode 13.0 (13A233) started me out with a project structure that matched my existing project.当我开始一个新项目用作 MWE 时,我注意到 Xcode 13.0 (13A233) 提供的 Storyboard 和 SwiftUI 界面选项都没有让我开始使用与我现有项目匹配的项目结构。 It was clear to me that SwiftUI was new and very different from my existing project, but the Storyboard interface wasn't familiar either and after several minutes a reading tutorials, I failed to build a storyboard app that would respond to button presses at all (all the storyboard app tutorials I found seemed to be set up for older versions of Xcode).我很清楚 SwiftUI 是新的,与我现有的项目非常不同,但故事板界面也不熟悉,在阅读了几分钟的教程后,我未能构建一个完全响应按钮按下的故事板应用程序(我发现的所有故事板应用程序教程似乎都是为旧版本的 Xcode 设置的)。

SwiftUI will require that you use @ObservedObject to react to changes in an object. SwiftUI 将要求您使用 @ObservedObject 对对象中的更改做出反应。 You can make this compliant with both observedobject and key-value manipulation as follows:您可以使这符合观察对象和键值操作,如下所示:

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
    }
}

You need to make the txt property available to Objective-C, in order to make it work with KVO/KVC.您需要使txt属性可用于 Objective-C,以便使其与 KVO/KVC 一起使用。 This is required as the Key-Value Observing/Coding mechanism is an Objective-C feature.这是必需的,因为键值观察/编码机制是 Objective-C 功能。

So, either所以,要么

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

, or , 或者

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

This will fix the error, and should make your app behave as expected.这将修复错误,并使您的应用程序按预期运行。 However, as others have said, you need to make more changes to the code in order to adhere to the SwiftUI paradigms.但是,正如其他人所说,您需要对代码进行更多更改以遵守 SwiftUI 范例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM