Как установить dat для просмотра из 2D-массива типа Api в SwiftUI?

У меня есть данные массива 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)")
                  }
                }
              }
        
    }
}

К сожалению, json, который вы получили, плохо разработан, поэтому, на мой взгляд, вы получите странную модель, с которой трудно иметь дело.

Joakim Danielson 11.11.2022 08:45
Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
1
1
87
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

попробуйте этот подход, работает для меня. Мне пришлось изменить несколько вещей в вашем коде, но это должно быть просто для понимания. Дайте мне знать, если вам нужны дополнительные пояснения.

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 в качестве заголовка столбца, как мне установить?

SwiftLearner 11.11.2022 09:37

обновил мой ответ возможным решением, чтобы получить заголовки для возможных столбцов.

workingdog support Ukraine 11.11.2022 10:27

Другие вопросы по теме