У меня есть данные массива 2D-типа в файле Json, и я хочу получить данные в модели просмотра. И я много раз пробовал и не смог получить данные. Я использовал модель, сгенерированную из QuickType.io И я использую шаблон MVVM для получение данных.
Это мои данные Json.
{ "publisherPlans": [[ "Name", "Free","Prime" ],["Book Sell",9999,9999],["Book Bulk Sell",0,9999],["Magazine start-up",9999,9999],["Demo book request count for School",5,9999],["Demo book request Acception",9999,9999],["Assign book for demo",25,9999]]}
А это моя модель, созданная веб-сайтом
public struct SchoolPlanModel: Decodable {
public let publisherPlans: [[PublisherPlan]]
}
public enum PublisherPlan:Decodable {
case integer(Int)
case string(String)
}
И это моя ViewModel, здесь я пытаюсь получить данные из файла Json.
class ReadData: ObservableObject {
@Published var datas = [String]()
func getData() async {
guard let url = URL(string: "********api/plans") else { return }
do {
let (data, _) = try await URLSession.shared.data(from: url)
Task{@MainActor in
let results = try JSONDecoder().decode(SchoolPlanModel.self, from: data).publisherPlans
print(results)
}
} catch {
print("---> error: \(error)")
}
}
}
Это мой вид Здесь я хочу показать данные.
struct SchoolPlanView: View{
@StateObject var list = ReadData()
var body: some View{
ForEach(list.datas,id: \.self) { array in
HStack{
ForEach(array.utf8CString, id: \.self) { element in
Text("\(element)")
}
}
}
}
}
попробуйте этот подход, работает для меня. Мне пришлось изменить несколько вещей в вашем коде, но это должно быть просто для понимания. Дайте мне знать, если вам нужны дополнительные пояснения.
struct ContentView: View {
var body: some View {
SchoolPlanView()
}
}
struct SchoolPlanModel: Decodable {
var publisherPlans: [[PublisherPlan]]
}
enum PublisherPlan: Decodable, Hashable {
case integer(Int)
case string(String)
// -- here
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let x = try? container.decode(Int.self) {
self = .integer(x)
return
}
if let x = try? container.decode(String.self) {
self = .string(x)
return
}
throw DecodingError.typeMismatch(PublisherPlan.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Plan"))
}
}
class ReadData: ObservableObject {
@Published var datas: [[PublisherPlan]] = [] // <-- here
func getData() async {
guard let url = URL(string: "https://myexampleurl.com") else { return }
do {
let (data, _) = try await URLSession.shared.data(from: url)
Task{@MainActor in
let results = try JSONDecoder().decode(SchoolPlanModel.self, from: data)
self.datas = results.publisherPlans // <-- here
}
} catch {
print("---> error: \(error)")
}
}
}
struct SchoolPlanView: View{
@StateObject var list = ReadData()
var body: some View {
// -- here
List(list.datas, id: \.self) { array in
HStack{
ForEach(array, id: \.self) { item in
switch item {
case .integer(let int): Text("\(int)")
case .string(let str): Text(str)
}
}
}
}
.task {
await list.getData() // <-- here
}
}
}
РЕДАКТИРОВАТЬ-1:
Чтобы получить заголовки для столбцов, попробуйте этот подход, где
вы разделяете данные и заголовки в источнике, в getData()
.
Вам нужно будет настроить отображение с помощью столбцов и т. д.
class ReadData: ObservableObject {
@Published var datas: [[PublisherPlan]] = []
@Published var headings: [String] = [] // <-- here
func getData() async {
guard let url = URL(string: "https://myexampleurl.com/plans") else { return }
do {
let (data, _) = try await URLSession.shared.data(from: url)
// print("\n \(String(data: data, encoding: .utf8) as AnyObject) \n")
Task{@MainActor in
let results = try JSONDecoder().decode(SchoolPlanModel.self, from: data)
// the data minus the first array of headings
datas = Array(results.publisherPlans.dropFirst()) // <-- here
// get the headings
if let headers = results.publisherPlans.first { // <-- here
for h in headers {
switch h {
case .integer(_): break
case .string(let str): self.headings.append(str)
}
}
}
}
} catch {
print("---> error: \(error)")
}
}
}
struct SchoolPlanView: View{
@StateObject var list = ReadData()
var body: some View {
VStack {
HStack {
ForEach(list.headings, id: \.self) { heading in // <-- here
Text(heading)
}
}
List(list.datas, id: \.self) { array in
HStack {
ForEach(array, id: \.self) { item in
switch item {
case .integer(let int): Text("\(int)")
case .string(let str): Text(str)
}
}
}
}
}
.task {
await list.getData()
}
}
}
это работает и для меня. @workingdog Я хочу установить Name, Free,Prime
в качестве заголовка столбца, как мне установить?
обновил мой ответ возможным решением, чтобы получить заголовки для возможных столбцов.
К сожалению, json, который вы получили, плохо разработан, поэтому, на мой взгляд, вы получите странную модель, с которой трудно иметь дело.