swiftui - 当变量被网络请求填充时如何初始化变量

标签 swiftui

我的内容 View 是:

struct ContentView {
   @State private var calendar = Bundle.main.decode(Calendar.self, from: "calendar.json")
   
    var body: some View {
        NavigationView {
           .... Content that loops through calendar and displays events in a list
        }
        .onAppear {
            self.getData()
        }
    }
}

func getData() {
     let url = "<URL goes here>"
     let encoded = "<JSON FOR REQUEST>"
 
     var request = URLRequest(url: url)
     request.setValue("application/json", forHTTPHeaderField: "Content-Type")
     request.httpMethod = "POST"
     let encoder = JSONEncoder()
     if let data = try? encoder.encode(encoded) {
         request.httpBody = data
     }
     URLSession.shared.dataTask(with: request) { data1, response, error in
     // DECODE the response and process the data
         if let data1 = data1 {
            let decoder = JSONDecoder()
            if let calendar = try? decoder.decode(IDCCalendar.self, from: data1)
            {
                self.calendar = calendar
            }
            else {
                print("Does not decode correctly")
            }
        }
        else {
            print("error with data1")
        }

 }.resume()
}

这是我的问题:日历变量需要初始化,因此我使用名为 calendar.json 的文件中的虚拟数据来初始化它。理想情况下,我只想声明 @State private var calendar : 日历 并让网络请求填充变量。使用虚拟数据方法,当应用程序加载时,首先出现虚拟数据,然后在网络调用完成时被实际数据替换。

任何解决此问题的建议将不胜感激。

最佳答案

如果您使用可选值,则无需为其设置初始值。您的View可以根据变量是否nil或有值进行有条件地渲染。

一般来说,异步请求不应在 View 内完成,因此我已将逻辑移至 ObservableObject:

class ViewModel : ObservableObject {
    @Published var calendar : CalendarModel?
    
    func getData() {
        //get data from API and set self.calendar with result
    }
}

struct ContentView {
    @StateObject var viewModel = ViewModel()
    
    var body: some View {
        NavigationView {
            Group {
                if let calendar = viewModel.calendar {
                    //use `calendar` variable here
                } else {
                    Text("Loading...")
                }
            }
        }
        .onAppear {
            viewModel.getData()
        }
    }
}

您还可以通过执行以下操作将日历 View 重构为其自己的组件(具有非可选属性):


struct ContentView {
    @StateObject var viewModel = ViewModel()
    
    var body: some View {
        NavigationView {
            Group {
                if let calendar = viewModel.calendar {
                    CalendarView(calendar: calendar)
                } else {
                    Text("Loading...")
                }
            }
        }
        .onAppear {
            viewModel.getData()
        }
    }
}

struct CalendarView : View {
    var calendar : CalendarModel
    
    var body: some View {
        //render calendar
    }
}

(注意:我使用了 CalendarModel,因为您没有包含类型的代码,并且您同时使用了 CalendarIDCCalendar,而且我不确定区别是什么。另外,请注意与 Calendar 的命名空间冲突,因为 Foundation 中已经有一个名为该类型的类型)

关于swiftui - 当变量被网络请求填充时如何初始化变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67373165/

相关文章:

swift - 在工作表内的表单中使用选取器不起作用

swift - 在 SwiftUI 文档应用程序中,如何从函数中保存文档

ios - 如何在 View 上创建扩展以在长按手势上显示警报 - SwiftUI

ios - SwiftUI:获取动态背景颜色(暗模式或亮模式)

ios - SwiftUI:UIAlertController 的 textField 在 UIAlertAction 中没有响应

macos - 如何在 SwiftUI 中为文本预留空间

swift - 对齐在 ios 14、xcode 12 swiftUI 中不起作用

ios - Swift UI 是否像 UIKit 一样具有类似于 viewDidLoad() 的功能?如果没有,如何创建这样一个在启动时调用的函数?

swift - 如何在 SwiftUI 的 ScrollView 中创建多行文本?

SwiftUI navigationView within Modal 'pushing' 查看向下