SwiftUI NavigationLink 在范围内找不到 'json'

SwiftUI NavigationLink cannot find 'json' in scope

我是 SwiftUI 的新手,已经完成了服务器请求和 JSON。我现在需要以编程方式转换到一个新视图,这是我在 ContentView.swift 中的 NavigationLink 上遇到“无法在范围内找到 'json'”错误的地方。我看过视频和文章,但没有完全匹配的内容,而且我尝试的一切似乎只会让事情变得更糟。

JSON 来自服务器的响应

{"status":{"errno":0,"errstr":""},
"data":[
{"home_id":1,"name":"Dave's House","timezone":"Australia\/Brisbane"},
{"home_id":2,"name":"Mick's House","timezone":"Australia\/Perth"},
{"home_id":3,"name":"Jim's House","timezone":"Australia\/Melbourne"}
]}

JSON 结构文件

import Foundation

struct JSONStructure: Codable {
    struct Status: Codable {
        let errno: Int
        let errstr: String
    }

    struct Home: Codable, Identifiable {
        var id = UUID()
        let home_id: Int
        let name: String
        let timezone: String
    }

    let status: Status
    let data: [Home]
}

ContentView 文件

import SwiftUI

struct ContentView: View {

    @State private var PushViewAfterAction = false
    
    var body: some View {

        NavigationLink(destination: ListView(json: json.data), isActive: $PushViewAfterAction) {
            EmptyView()
        }.hidden()
        
        Button(action: {
            Task {
                await performAnAction()
            }
        }, label: {
            Text("TEST")
                .padding()
                .frame(maxWidth: .infinity)
                .background(Color.blue.cornerRadius(10))
                .foregroundColor(.white)
                .font(.headline)
        })
        
    }

    func performAnAction() {
        PushViewAfterAction = true
        return
    }

}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

列表视图文件

import SwiftUI

struct ListView: View {
    
    @State var json: JSONStructure

    var body: some View {

        VStack {
             
            List (self.json.data) { (home) in
                HStack {
                    Text(home.name).bold()
                    Text(home.timezone)
                }
            }
             
        }.onAppear(perform: {
            
            guard let url: URL = URL(string: "https://... ***removed*** ") else {
                print("invalid URL")
                return
            }
             
            var urlRequest: URLRequest = URLRequest(url: url)
            urlRequest.httpMethod = "POST"
            
            URLSession.shared.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
                // check if response is okay
                 
                guard let data = data, error == nil else { // check for fundamental networking error
                    print((error?.localizedDescription)!)
                    return
                }
                            
                let httpResponse = (response as? HTTPURLResponse)!
                            
                if httpResponse.statusCode != 200 { // check for http errors
                    print("httpResponse Error: \(httpResponse.statusCode)")
                    return
                }
                 
                // convert JSON response
                do {
                    self.json = try JSONDecoder().decode(JSONStructure.self, from: data)
                } catch {
                    print(error.localizedDescription)
                    print(String(data: data, encoding: String.Encoding.utf8)!)
                }
                
                print(json)
                
                if (json.status.errno != 0) {
                    print(json.status.errstr)
                }
                
                print("1. \(json.data[0].name)), \(json.data[0].timezone)")
                print("2. \(json.data[1].name)), \(json.data[1].timezone)")
                
            }).resume()
        })
        
    }
}

struct ListView_Previews: PreviewProvider {
    static var previews: some View {
        ListView()
    }
}

为了清楚起见,我尽量将代码保持在最低限度。

是因为ContentView中没有“json”,所以需要将json对象传递给ListView,但是既然在ListView中加载了json,那么就需要初始化json 在 ListView 中像:

struct ListView: View {

    @State var json: JSONStructure = JSONStructure(status: JSONStructure.Status(errno: 0, errstr: ""), data: [JSONStructure.Home(home_id: 0, name: "", timezone: "")])

    var body: some View {

并将其从 ContentView 中的 NavigationLink 中删除,例如:

NavigationLink(destination: ListView(), isActive: $PushViewAfterAction) {

或者您可以构建 JSONStructure 以接受可选的,例如:

import Foundation

struct JSONStructure: Codable {
    struct Status: Codable {
        let errno: Int?
        let errstr: String?
        init() {
            errno = nil
            errstr = nil
        }
    }

    struct Home: Codable, Identifiable {
        var id = UUID()
        let home_id: Int?
        let name: String?
        let timezone: String?

        init() {
            home_id = nil
            name = nil
            timezone = nil
        }
    }

    let status: Status?
    let data: [Home]

    init() {
        status = nil
        data = []
    }
  }

但是您需要检查可选值或提供默认值,例如:

构造 ListView:视图 {

@State var json: JSONStructure = JSONStructure()

var body: some View {

    VStack {

        List (self.json.data) { (home) in
            HStack {
                Text(home.name ?? "Could not get name").bold()
                Text(home.timezone ?? "Could not get timeZone")
            }
        }

    }.onAppear(perform: {

        guard let url: URL = URL(string: "https://... ***removed*** ") else {
            print("invalid URL")
            return
        }

        var urlRequest: URLRequest = URLRequest(url: url)
        urlRequest.httpMethod = "POST"

        URLSession.shared.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
                // check if response is okay

            guard let data = data, error == nil else { // check for fundamental networking error
                print((error?.localizedDescription)!)
                return
            }

            let httpResponse = (response as? HTTPURLResponse)!

            if httpResponse.statusCode != 200 { // check for http errors
                print("httpResponse Error: \(httpResponse.statusCode)")
                return
            }

                // convert JSON response
            do {
                self.json = try JSONDecoder().decode(JSONStructure.self, from: data)
            } catch {
                print(error.localizedDescription)
                print(String(data: data, encoding: String.Encoding.utf8)!)
            }

            print(json)

            if (json.status?.errno != 0) {
                print(json.status?.errstr)
            }

            print("1. \(json.data[0].name)), \(json.data[0].timezone)")
            print("2. \(json.data[1].name)), \(json.data[1].timezone)")

        }).resume()
    })

}

}