我正在努力使用iOS 17和SwiftData的SwiftUI应用程序。我试图从JSON源下载数据并将数据存储在SwiftData中。我可以将数据下载并解码到Swift结构中,但无法使用SwiftData @Model类。下面的代码包括结构和SwiftData过程。SwiftData类是SDTopLevel和SDFuelStation,结构体为TopLevelX和FuelStationX。FuelStationListView中的按钮调用loadDataSD或loadDataX。URL正确且包含演示密钥。
struct FuelStationListView: View {
@Environment(\.modelContext) var context
@Query(sort: \SDFuelStation.stationName) var fuelStations: [SDFuelStation]
@State private var sdTopLevel: SDTopLevel?
@State private var topLevel: TopLevelX?
var body: some View {
NavigationStack {
Button("Fetch") {
Task {
await loadDataX()//works
//await loadDataSD()//does not work
}
}
List {
ForEach(fuelStations) { fuelStation in
Text(fuelStation.stationName)
}
}
.navigationTitle("Fuel Stations")
}//nav
}//body
func loadDataSD() async {
guard let url = URL(string: "https://developer.nrel.gov/api/alt-fuel-stations/v1.json?api_key=DEMO_KEY&limit=10") else {
print("Invalid URL")
return
}
do {
let (data, response) = try await URLSession.shared.data(from: url)
guard (response as? HTTPURLResponse)?.statusCode == 200 else {
print(response)
return
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decodedResponse = try decoder.decode(SDTopLevel.self, from: data)
print(decodedResponse)
sdTopLevel = decodedResponse
print("sdTopLevel.fuelStations.count is \(sdTopLevel?.fuelStations.count ?? 1000)")
} catch {
print("Invalid Data")
}
}//load data
func loadDataX() async {
guard let url = URL(string: "https://developer.nrel.gov/api/alt-fuel-stations/v1.json?api_key=DEMO_KEY&limit=10") else {
print("Invalid URL")
return
}
do {
let (data, response) = try await URLSession.shared.data(from: url)
guard (response as? HTTPURLResponse)?.statusCode == 200 else {
print(response)
return
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decodedResponse = try decoder.decode(TopLevelX.self, from: data)
self.topLevel = decodedResponse
print("topLevel.fuelStations.count is \(topLevel?.fuelStations.count ?? 0)")
for station in decodedResponse.fuelStations {
print(station.stationName)
}
self.topLevel = nil
} catch {
print("Invalid Data")
}
}//load data
}//struct fuel Station list view
字符串
数据显示:
@Model
class SDFuelStation: Codable {
enum CodingKeys: CodingKey {
case id, city, stationName, streetAddress
}//enum
public var id: Int
var stationName: String = ""
var streetAddress: String = ""
var city: String = ""
public init(stationName: String, streetAddress: String, city: String) {
self.id = 0
self.stationName = stationName
self.streetAddress = streetAddress
self.city = city
}
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
stationName = try container.decode(String.self, forKey: .stationName)
streetAddress = try container.decode(String.self, forKey: .streetAddress)
city = try container.decode(String.self, forKey: .city)
}//required init
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(stationName, forKey: .stationName)
try container.encode(streetAddress, forKey: .streetAddress)
try container.encode(city, forKey: .city)
}
}//class
struct TopLevelX: Codable {
let fuelStations: [FuelStationX]
}
struct FuelStationX: Codable {
let id: Int
var stationName: String = ""
var streetAddress: String = ""
var city: String = ""
}//struct
型
错误发生在getter中的Model代码中:
x1c 0d1x的数据
任何指导将不胜感激。Xcode 15.0
编辑:我错误地错过了SDTopLevel类:
@Model
class SDTopLevel: Codable {
enum CodingKeys: CodingKey {
case fuelStations
}
var fuelStations: [SDFuelStation]
init(fuelStations: [SDFuelStation]) {
self.fuelStations = fuelStations
}
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
fuelStations = try container.decode([SDFuelStation].self, forKey: .fuelStations)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(fuelStations, forKey: .fuelStations)
}
}
型
var fuelStations的代码如下展开,错误在行上:return self.getValue(forKey:.fuelStations),错误是“Thread 10:EXC_BREAKPOINT(code=1,subcode= 0x 1a 8a 5303 c)”
{
@storageRestrictions(accesses: _$backingData, initializes: _fuelStations)
init(initialValue) {
_$backingData.setValue(forKey: \.fuelStations, to: initialValue)
_fuelStations = _SwiftDataNoType()
}
get {
_$observationRegistrar.access(self, keyPath: \.fuelStations)
return self.getValue(forKey: \.fuelStations)
}
set {
_$observationRegistrar.withMutation(of: self, keyPath: \.fuelStations) {
self.setValue(forKey: \.fuelStations, to: newValue)
}
}
}
型
2条答案
按热度按时间jhkqcmku1#
解决方案与我们在Core Data中所做的非常相似,我们需要将模型上下文传递给解码器,以便我们可以在
init(from:)
中使用它并插入顶级对象。为此,我们在JSONDecoder上使用
userInfo
字典,因此首先需要定义一个键字符串
然后在解码之前,我们将
ModelContext
的Environment
变量传递给解码器型
然后,我们读取这个键,并在
init(from:)
中使用它作为json的根对象型
我们不需要对
SDFuelStation
做同样的事情,因为如果关系的一端已经插入到模型上下文中,那么对于SwiftData就足够了。xxb16uws2#
尝试这种方法,在其中声明
SDTopLevel
和SDFuelStation
之间的关系。将json数据直接解码为model类型效果非常好,如本示例代码所示。
字符串