【问题标题】:SwiftUI: String property of an object is not displaying in Text, and how would you edit a string in an object?SwiftUI:对象的字符串属性未显示在文本中,您将如何编辑对象中的字符串?
【发布时间】:2021-10-24 02:30:22
【问题描述】:

我对 Swift 编程非常陌生。所以我试图想出一个时间管理程序。我已经发布了一些从我的项目中派生的代码,这些代码正在进行中,我正在尝试解决一些由于我对 Swift 和 SwiftUI 缺乏知识而遇到的问题。我想在这里问两个问题,但如果您只有其中一个问题的答案,我将不胜感激。

因此,在我的 ContentView 中,我尝试使用 VStack 中的 Text 显示 ID 为 0 的对象的 taskName - 但是,它没有显示,我不确定原因。我可以通过将它放在 String 方法中来显示 taskLength,但是当我尝试显示它时没有出现 taskName。

我还尝试更改直接从 display2 传递到 display2 的 Task(id: 0) 的 taskName,但我不确定 Task(id: 0) 的 taskName 是否实际上正在更改, 或者只是 display2 中 @State var task:Task 的 taskName 正在改变——根据我的直觉,我认为后一种情况实际上正在发生。那么有没有办法直接从display2编辑Task(id: 0)的taskName?

import SwiftUI
import Foundation
import Combine

struct Task: Hashable, Codable, Identifiable {
    var id: Int
    var taskName: String = ""
    var taskLength: Int = 0
    var isBreak : Bool = false
}

class ModelData : ObservableObject{
    @Published var tasks: [Task] = [
        Task(id: 0,taskName: "Test", taskLength: 34, isBreak: false),
        Task(id: 1,taskName: "Math", taskLength: 30, isBreak: false),
        Task(id: 2,taskName: "Science", taskLength: 40, isBreak: false)
    ]
}

struct ContentView: View {
    @EnvironmentObject var modelData: ModelData
    var body: some View {
        VStack{
            Text(Task(id: 0).taskName)
            display2(task:Task(id: 0))
        }
    }
}

struct display2: View{
    @State var task:Task
    var body: some View {
        TextField("New task",text: $task.taskName)
    }
}

【问题讨论】:

    标签: arrays swift object swiftui


    【解决方案1】:

    问题出在这里:

    Text(Task(id: 0).taskName)
    

    在这里,您正在创建一个 Taskid 为 0。这不是在您的 ModelData 中的第一个任务tasks 数组。

    改为通过下标[]引用第一个任务:

    Text(modelData.tasks[ /* index of task */ ].taskName)
    

    通常您只需将0 放在这里即可获得第一个Task。但是,您说您实际上想要Task 0id。您可以通过firstIndex(where:) 进行此操作。

    struct ContentView: View {
        @EnvironmentObject var modelData: ModelData
        var body: some View {
            VStack{
                Text(
                    modelData.tasks[getTaskIndexFrom(id: 0)] /// access 
                        .taskName
                )
                
                Display2( /// see https://stackoverflow.com/a/67064699/14351818
                    task: $modelData.tasks[getTaskIndexFrom(id: 0)]
                )
            }
        }
        func getTaskIndexFrom(id: Int) -> Int {
            
            /// get first index of a task with the specified `id`
            if let firstIndex = modelData.tasks.firstIndex(where: { $0.id == 0 }) {
                return firstIndex
            } else {
                return 0
            }
        }
    }
    
    struct Display2: View{
        @Binding var task: Task /// need a Binding here
        var body: some View {
            TextField("New task", text: $task.taskName)
        }
    }
    

    好的,你的第二个问题:

    这样的话,有没有办法直接从display2编辑Task(id:0)的taskName?

    是的!只需在Display2task 上使用@Binding。这样,所有更改都会同步回您的modelData

    【讨论】:

    • 感谢您的回复——非常详细。但是我尝试复制您提供的代码,但我遇到了一个致命错误。线程 1:致命错误:未找到 ModelData 类型的 ObservableObject。 ModelData 的 View.environmentObject(_:) 作为该视图的祖先可能会丢失。
    • 确保在YourApp.swift 中,您执行ContentView().environmentObject(ModelData()) 或类似操作。 Taeeun Kim's answer中也提到了这一点。
    • 是的,我这样做了,但问题仍然存在。没关系;在我的主程序中,我实现了访问你给我的第一个任务并使用@Binding 的语法,它成功了!所以最后,你的解决方案对我有用——非常感谢。
    • @swiftNewb 好的,很好!如果有效,您可以按绿色复选标记接受答案吗?
    • 当然。感谢回复
    【解决方案2】:

    在 ContentView 中您只使用了 Task(),但您必须在 ModelData 中使用 modelData 来代替 @Published var tasks




    Task(id: 0).taskName -> modelData.tasks[1].taskName

    struct ContentView: View {
        @EnvironmentObject var modelData: ModelData
        
        var body: some View {
            VStack{
                Text(modelData.tasks[1].taskName)
                    .foregroundColor(.blue)
                display2(task:Task(id: 0))
            }
        }
    }
    



    另外,只要你使用@EnvironmentObject,你也需要将.environmentObject添加到main中。
    (下面的代码是一个SwiftUI生命周期的例子)

    import SwiftUI
    
    @main
    struct ReplyToStackoverflowApp: App {
        var modelData: ModelData = ModelData()
        
        var body: some Scene {
            WindowGroup {
                ContentView()
                    .environmentObject(modelData)
            }
        }
    }
    



    【讨论】:

    • 啊,好的,非常感谢!非常感谢您的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-28
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    • 2021-10-28
    • 2023-02-09
    • 2011-10-05
    相关资源
    最近更新 更多