在 SwiftUI 中迭代 Codable 数组
Iterating over array of Codable in SwiftUI
作为 的后续行动,我现在想在 SwiftUI 中循环访问 Codable 结构数组,并在我的 ContentView{} 中将它们呈现为文本或列表项。
我尝试在 .task
部分实现一个变量 geoDataArray
,然后在我的 ContentView
部分用 ForEach
对其进行迭代,但收到了很多错误关于类型和展开值。
感谢任何帮助!我还是 SwiftUI 的新手。
下面是我的代码:
struct GeoService: Codable {
var status: String
var results: [GeoResult]
}
struct GeoResult: Codable {
struct Geometry: Codable {
struct Location: Codable {
let lat: Float
let lng: Float
init() {
lat = 32
lng = 30
}
}
let location: Location
}
let formatted_address: String
let geometry: Geometry
}
struct ContentView: View {
// @State private var results: Any ?????????
var body: some View {
NavigationView {
Text("Test")
.navigationTitle("Quotes")
.task {
await handleData()
}
}
}
func handleData() async {
let geoResult="""
{
"results": [
{
"formatted_address": "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA",
"geometry": {
"location": {
"lat": 37.4224764,
"lng": -122.0842499
}
}
},
{
"formatted_address": "Test addresss",
"geometry": {
"location": {
"lat": 120.32132145,
"lng": -43.90235469
}
}
}
],
"status": "OK"
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
print("executing handleData()")
do {
let obj = try decoder.decode(GeoService.self, from: geoResult)
for result in obj.results {
print("Address: \(result.formatted_address)")
print("Lat/long: (\(result.geometry.location.lat), \(result.geometry.location.lng))")
}
} catch {
print("Did not work :(")
}
}
}
您的代码在打印到控制台时工作正常,但是 ForEach
要求 GeoResult
符合 Identifiable
(首选)或至少 Hashable
.鉴于您没有在代码中包含 属性 id
,让我们让该结构符合 Hashable
.
所以,假设每个 GeoResult
是不同的,因为 formatted_address
永远不一样(你必须检查它是否正确),你可以添加两个确保一致性的功能。您将获得以下内容:
struct GeoResult: Codable, Hashable { // <- Conform to Hashable
// Differentiating
static func == (lhs: GeoResult, rhs: GeoResult) -> Bool {
lhs.formatted_address == rhs.formatted_address
}
// Hashing
func hash(into hasher: inout Hasher) {
hasher.combine(formatted_address)
}
struct Geometry: Codable {
struct Location: Codable {
let lat: Float
let lng: Float
init() {
lat = 32
lng = 30
}
}
let location: Location
}
let formatted_address: String
let geometry: Geometry
}
在视图中,添加一个 GeoResult
数组,这将是要迭代的 @State
变量。将 .task()
修饰符放在最外面的视图上。
// This is the list
@State private var geoArray: [GeoResult] = []
var body: some View {
NavigationView {
VStack {
// GeoResult is not Identifiable, so it is necessary to include id: \.self
ForEach(geoArray, id: \.self) { result in
NavigationLink {
Text("Lat/long: (\(result.geometry.location.lat), \(result.geometry.location.lng))")
} label: {
Text("Address: \(result.formatted_address)")
}
}
.navigationTitle("Quotes")
}
}
// Attach the task to the outermost view, in this case the NavigationView
.task {
await handleData()
}
}
最后,解码后更改函数中的 @State
变量:
func handleData() async {
// ...
let decoder = JSONDecoder()
do {
let obj = try decoder.decode(GeoService.self, from: geoResult)
// Add this
geoArray = obj.results
} catch {
print("Did not work :(\n\(error)")
}
}
作为
我尝试在 .task
部分实现一个变量 geoDataArray
,然后在我的 ContentView
部分用 ForEach
对其进行迭代,但收到了很多错误关于类型和展开值。
感谢任何帮助!我还是 SwiftUI 的新手。
下面是我的代码:
struct GeoService: Codable {
var status: String
var results: [GeoResult]
}
struct GeoResult: Codable {
struct Geometry: Codable {
struct Location: Codable {
let lat: Float
let lng: Float
init() {
lat = 32
lng = 30
}
}
let location: Location
}
let formatted_address: String
let geometry: Geometry
}
struct ContentView: View {
// @State private var results: Any ?????????
var body: some View {
NavigationView {
Text("Test")
.navigationTitle("Quotes")
.task {
await handleData()
}
}
}
func handleData() async {
let geoResult="""
{
"results": [
{
"formatted_address": "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA",
"geometry": {
"location": {
"lat": 37.4224764,
"lng": -122.0842499
}
}
},
{
"formatted_address": "Test addresss",
"geometry": {
"location": {
"lat": 120.32132145,
"lng": -43.90235469
}
}
}
],
"status": "OK"
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
print("executing handleData()")
do {
let obj = try decoder.decode(GeoService.self, from: geoResult)
for result in obj.results {
print("Address: \(result.formatted_address)")
print("Lat/long: (\(result.geometry.location.lat), \(result.geometry.location.lng))")
}
} catch {
print("Did not work :(")
}
}
}
您的代码在打印到控制台时工作正常,但是 ForEach
要求 GeoResult
符合 Identifiable
(首选)或至少 Hashable
.鉴于您没有在代码中包含 属性 id
,让我们让该结构符合 Hashable
.
所以,假设每个 GeoResult
是不同的,因为 formatted_address
永远不一样(你必须检查它是否正确),你可以添加两个确保一致性的功能。您将获得以下内容:
struct GeoResult: Codable, Hashable { // <- Conform to Hashable
// Differentiating
static func == (lhs: GeoResult, rhs: GeoResult) -> Bool {
lhs.formatted_address == rhs.formatted_address
}
// Hashing
func hash(into hasher: inout Hasher) {
hasher.combine(formatted_address)
}
struct Geometry: Codable {
struct Location: Codable {
let lat: Float
let lng: Float
init() {
lat = 32
lng = 30
}
}
let location: Location
}
let formatted_address: String
let geometry: Geometry
}
在视图中,添加一个 GeoResult
数组,这将是要迭代的 @State
变量。将 .task()
修饰符放在最外面的视图上。
// This is the list
@State private var geoArray: [GeoResult] = []
var body: some View {
NavigationView {
VStack {
// GeoResult is not Identifiable, so it is necessary to include id: \.self
ForEach(geoArray, id: \.self) { result in
NavigationLink {
Text("Lat/long: (\(result.geometry.location.lat), \(result.geometry.location.lng))")
} label: {
Text("Address: \(result.formatted_address)")
}
}
.navigationTitle("Quotes")
}
}
// Attach the task to the outermost view, in this case the NavigationView
.task {
await handleData()
}
}
最后,解码后更改函数中的 @State
变量:
func handleData() async {
// ...
let decoder = JSONDecoder()
do {
let obj = try decoder.decode(GeoService.self, from: geoResult)
// Add this
geoArray = obj.results
} catch {
print("Did not work :(\n\(error)")
}
}