如何解决 API 在 SwiftUI 中调用 JSON

How to troubleshoot API Call JSON in SwiftUI

我正在对 Rails 服务器进行 API 调用以获取 objects 的数组,然后在 SwiftUI 视图中显示这些 objects。

当我在 Postman 中进行同样的 API 调用时,它工作正常。我收到回复了。

当我在我的 SwiftUI 项目中进行相同的调用时,我似乎没有正确保存对我的模型的响应,否则我 运行 会出错。我的服务器似乎可以正常发送数据。视图加载,但列表为空,只有“您的项目”的导航标题

正在寻找有关如何检查我的响应数组是否正在存储数据以及如何进行故障排除的指导。视图从该数组加载数据,但它似乎是空的。

我使用 quicktype.io 从 Postman JSON 提供的服务器映射模型结构。

这是模型的相关部分:

import Foundation

struct ProjectFetchRequest: Decodable {
let request: [ProjectResponseObjectElement]
}

// MARK: - ProjectResponseObjectElement
struct ProjectResponseObjectElement: Codable, Identifiable {
let id = UUID()
let project: Project
let projectType: ProjectType
let inspirations: [JSONAny]
}

// MARK: - Project
struct Project: Codable {
let name: String
let id: Int
let projectType, timeframe, description: String
let currentProgress: Int
let zipcode, status, createdAt, visibility: String
let city, state: String
let title: String
let showURL: String
let thumbnailURL: String
let ownedByLoggedinUser, hasBids, isPublished: Bool
}

// MARK: - ProjectType
struct ProjectType: Codable {
let generalConstructions, landscapes: [GeneralConstruction]?
}

// MARK: - GeneralConstruction
struct GeneralConstruction: Codable {
let id: Int
}

typealias ProjectResponseObject = [ProjectResponseObjectElement]

这是 API 调用:

import Foundation

final class Projectservice {

static let shared = Projectservice()

private init() {}

func fetchProjects(completed: @escaping (Result<[ProjectResponseObjectElement], AuthenticationError>) -> Void) {
        
    guard let url = URL(string: "https://example.com/api/v1/projects") else {
        completed(.failure(.custom(errorMessage:"URL unavailable")))
        return
    }
    
    guard let Accesstoken = UserDefaults.standard.string(forKey: "access-token") else { return }
    guard let client = UserDefaults.standard.string(forKey: "client") else { return }
    guard let uid = UserDefaults.standard.string(forKey: "userEmail") else { return }
    
    print(Accesstoken)
    print(client)
    print(uid)
    
    var request = URLRequest(url: url)
            request.httpMethod = "GET"
            request.addValue("application/json", forHTTPHeaderField: "Content-Type")
            request.addValue(Accesstoken, forHTTPHeaderField: "access-token")
            request.addValue(client, forHTTPHeaderField: "client")
            request.addValue(uid, forHTTPHeaderField: "uid")
            request.addValue("Bearer", forHTTPHeaderField: "Tokentype")
    
    URLSession.shared.dataTask(with: request) { (data, response, error) in
        
        guard let data = data, error == nil else { return }
        guard let projectResponse = try? JSONDecoder().decode(ProjectFetchRequest.self, from: data) else { return }
        completed(.success(projectResponse.request))
        print(projectResponse)
    }.resume()
}
}

视图如下:

import SwiftUI

struct ProjectsView: View {

@State private var projectObjects: [ProjectResponseObjectElement] = []

var body: some View {
    NavigationView{
        List(projectObjects){ projectObject in
            ProjectRowView(project: projectObject.project)
        }
        .navigationTitle("Your Projects")
        .foregroundColor(.primary)
    }.navigationViewStyle(StackNavigationViewStyle())
    .onAppear {
        fetchProjects()
    }
}
func fetchProjects() {
    Projectservice.shared.fetchProjects { result in
        DispatchQueue.main.async {
            switch result {
            case .success(let projectObjects):
                self.projectObjects = projectObjects
            case .failure(let error):
                print(error.localizedDescription)
            }
        }
    }
}
}

我需要在 URLSession 中声明顶级数组结构。

import Foundation

final class Projectservice {

static let shared = Projectservice()

private init() {}

func fetchProjects(completed: @escaping (Result<[ProjectResponseObjectElement], AuthenticationError>) -> Void) {
        
    guard let url = URL(string: "https://example.com/api/v1/projects") else {
        completed(.failure(.custom(errorMessage:"URL unavailable")))
        return
    }
    
    guard let Accesstoken = UserDefaults.standard.string(forKey: "access-token") else { return }
    guard let client = UserDefaults.standard.string(forKey: "client") else { return }
    guard let uid = UserDefaults.standard.string(forKey: "userEmail") else { return }
    
    print(Accesstoken)
    print(client)
    print(uid)
    
    var request = URLRequest(url: url)
            request.httpMethod = "GET"
            request.addValue("application/json", forHTTPHeaderField: "Content-Type")
            request.addValue(Accesstoken, forHTTPHeaderField: "access-token")
            request.addValue(client, forHTTPHeaderField: "client")
            request.addValue(uid, forHTTPHeaderField: "uid")
            request.addValue("Bearer", forHTTPHeaderField: "Tokentype")
    
    URLSession.shared.dataTask(with: request) { (data, response, error) in
        
        guard let data = data, error == nil else { return }
        do {
         let projectResponse = try JSONDecoder().decode([ProjectResponseObjectElement].self, from: data)
         completed(.success(projectResponse))
        } catch {
            print(error)
        }
    }.resume()
}
}