SwiftUI NavigationLink 在范围内找不到“json”
Posted
技术标签:
【中文标题】SwiftUI NavigationLink 在范围内找不到“json”【英文标题】:SwiftUI NavigationLink cannot find 'json' in scope 【发布时间】: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()
为了清晰起见,我尽量将代码保持在最低限度。
【问题讨论】:
【参考方案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()(这就是我所做的,因为我不这样做拥有我正在使用的服务器)以上是关于SwiftUI NavigationLink 在范围内找不到“json”的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 上的 NavigationLink 两次推送视图
SwiftUI:NavigationLink 内的水平 ScrollView 会中断导航
有没有办法向 NavigationLink 添加额外的功能? SwiftUI