【问题标题】:SwiftUI NavigationLink cannot find 'json' in scopeSwiftUI NavigationLink 在范围内找不到“json”
【发布时间】:2022-01-01 03:05:52
【问题描述】:

我是 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]
}

内容视图文件

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

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

【问题讨论】:

    标签: json swiftui scope swiftui-navigationlink


    【解决方案1】:

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

    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 = []
        }
      }
    

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

    结构列表视图:查看{

    @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()
        })
    
    }
    

    }

    【讨论】:

    • 谢谢穆斯塔法。第一个选项似乎是最简单的,并且在成功构建代码和查看转换工作方面效果很好。但是,当我返回数据数组中的数据时,更改破坏了 JSONDecoder,我无法弄清楚。
    • 数据丢失,无法读取。 {"status":{"errno":1,"errstr":"Test message"},"data":[{"home_id":1,"name":"Dave's House","timezone":"Australia\ /布里斯班"},{"home_id":2,"name":"Mick's House","timezone":"澳大利亚\/珀斯"},{"home_id":3,"name":"Jim's House"," timezone":"Australia\/Melbourne"}]} 打印 JSON JSONStructure(status: jsontest.JSONStructure.Status(errno: 0, errstr: ""), data: [jsontest.JSONStructure.Home(id: 42D7B889-46F4-40C8 -8E2D-C740CBE26751, home_id: 0, name: "", timezone: "")])
    • @Mick 将 print(error.localizedDescription) 替换为 print(error)。这显示了一条详细的错误消息,即 JSON 中没有键 id 替换 Home
    • 谢谢@vadian 我现在更好地理解了可识别性,并更改了 MySQL 给我一个“id”,直到我更好地掌握 SwiftUI。现在一切正常。
    • 不客气@Mick,对不起,我忘了告诉你id,你要么从服务器提供它,要么在解码时使用 UUID()(这就是我所做的,因为我不这样做拥有我正在使用的服务器)
    猜你喜欢
    • 2020-12-31
    • 1970-01-01
    • 2023-01-26
    • 1970-01-01
    • 2021-09-14
    • 1970-01-01
    • 2020-11-23
    • 2021-06-18
    • 2021-01-15
    相关资源
    最近更新 更多