“期望解码字典< string,任何>但是找到了一个阵列。&quot&quot ofstlyingerror:nil; github repo显示应用程序;斯威夫特

发布于 2025-01-23 03:45:29 字数 1604 浏览 5 评论 0原文

我需要创建一个应用程序,该应用程序将能够返回GitHub用户拥有的所有存储库。

我创建了一个包含3个文件的应用程序: Content View

import SwiftUI

struct ContentView: View {
    
    @StateObject var netManager = NetworkingManager()
    
    
    var body: some View {
            List {
                ForEach(netManager.owner) { item in
                    Text(item.reposUrl)
                }
        }
    }
}

API键

import Foundation

struct Root : Decodable, Identifiable {
    let id: Int
    let items : [Repository]
}

struct Repository: Decodable, Identifiable {
    let id: Int
    let name, fullName: String
    let owner : Owner
}

struct Owner : Decodable, Identifiable {
    let id: Int
    let reposUrl : String
}

解码器(因为我知道我应该以后再需要另一个,除非我能够将其抽象足够),否则

class NetworkingManager: ObservableObject{
    @Published var owner = [Owner]()
    
    init() {
            loadData()
        }

        func loadData() {
            guard let url = URL(string: "https://api.github.com/users/jacobtoye/repos") else { return }
            URLSession.shared.dataTask(with: url) {(data, _, _) in
                guard let data = data else { return }
                do {
                    let response = try JSONDecoder().decode(Owner.self, from: data)
                } catch {
                    print("error: \(error)")
                }
                
            }.resume()
        }
        
    }

代码运行良好,但我没有得到任何结果(第一个屏幕是空白),我想看看那里选择的用户存储库的列表。您能帮我解码字典吗?

我也想知道问题是否不在于我也没有使用convertfromsnakecase密钥解码策略,但是当jsondecoder被固定包装时,我不知道如何将其放在那里。

I need to create an app that will be able to return all the repositories that a GitHub user owns.

I created an app that contains of 3 files:
CONTENT VIEW

import SwiftUI

struct ContentView: View {
    
    @StateObject var netManager = NetworkingManager()
    
    
    var body: some View {
            List {
                ForEach(netManager.owner) { item in
                    Text(item.reposUrl)
                }
        }
    }
}

API KEYS

import Foundation

struct Root : Decodable, Identifiable {
    let id: Int
    let items : [Repository]
}

struct Repository: Decodable, Identifiable {
    let id: Int
    let name, fullName: String
    let owner : Owner
}

struct Owner : Decodable, Identifiable {
    let id: Int
    let reposUrl : String
}

DECODERS (since I know I should need another one later, unless I can abstract this one enough)

class NetworkingManager: ObservableObject{
    @Published var owner = [Owner]()
    
    init() {
            loadData()
        }

        func loadData() {
            guard let url = URL(string: "https://api.github.com/users/jacobtoye/repos") else { return }
            URLSession.shared.dataTask(with: url) {(data, _, _) in
                guard let data = data else { return }
                do {
                    let response = try JSONDecoder().decode(Owner.self, from: data)
                } catch {
                    print("error: \(error)")
                }
                
            }.resume()
        }
        
    }

The code runs fine, but I don't get any results (the first screen is blank) and I would like to see a list of the chosen user repos there. Could you please help me decode the dictionary?

I also wonder if the problem doesn't lie with that I didn't use convertFromSnakeCase key Decoding Strategy either, but I don't know how to put it there when the JSONDecoder is wrapped in a constant.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

沧桑㈠ 2025-01-30 03:45:29

对于极简主义的工作示例代码,请尝试以下操作:

struct Repository: Decodable, Identifiable {
    let id: Int
    let name, fullName: String
    let owner: Owner
    
    enum CodingKeys: String, CodingKey {
        case id, name, owner
        case fullName = "full_name"  // <-- here
    }
}

struct Owner : Decodable, Identifiable {
    let id: Int
    let reposUrl : String

    enum CodingKeys: String, CodingKey, CaseIterable {
        case id
        case reposUrl = "repos_url"  // <-- here
    }
}

class NetworkingManager: ObservableObject{
    @Published var owner = [Owner]()
    
    init() {
        loadData()
    }
    
    func loadData() {
        guard let url = URL(string: "https://api.github.com/users/jacobtoye/repos") else { return }
        URLSession.shared.dataTask(with: url) {(data, _, _) in
            guard let data = data else { return }
            DispatchQueue.main.async { // <-- here
                do {
                    let repos = try JSONDecoder().decode([Repository].self, from: data)  // <-- here
                    repos.forEach{ self.owner.append($0.owner) }
                } catch {
                    print("error: \(error)")
                }
           }
        }.resume()
    }
}

struct ContentView: View {
    @StateObject var netManager = NetworkingManager()
    
    var body: some View {
        List {
            ForEach(netManager.owner) { item in
                Text(item.reposUrl)
            }
        }
    }
}

这应该为您提供“ https://api.github.com/users/jacobtoye/repos”的列表。

编辑1:列出所有存储库

class NetworkingManager: ObservableObject{
    @Published var repos = [Repository]() // <-- here repos
    
    init() {
        loadData()
    }
    
    func loadData() {
        guard let url = URL(string: "https://api.github.com/users/jacobtoye/repos") else { return }
        URLSession.shared.dataTask(with: url) {(data, _, _) in
            guard let data = data else { return }
            DispatchQueue.main.async { // <-- here
                do {
                    self.repos = try JSONDecoder().decode([Repository].self, from: data)  // <-- here
                } catch {
                    print("error: \(error)")
                }
            }
        }.resume()
    }
}

struct ContentView: View {
    @StateObject var netManager = NetworkingManager()
    
    var body: some View {
        List {
            ForEach(netManager.repos) { repo in
              VStack {
                Text(repo.fullName).foregroundColor(.blue)
                Text(repo.owner.reposUrl)
              }
            }
        }
    }
}

for a minimalist working example code, try this:

struct Repository: Decodable, Identifiable {
    let id: Int
    let name, fullName: String
    let owner: Owner
    
    enum CodingKeys: String, CodingKey {
        case id, name, owner
        case fullName = "full_name"  // <-- here
    }
}

struct Owner : Decodable, Identifiable {
    let id: Int
    let reposUrl : String

    enum CodingKeys: String, CodingKey, CaseIterable {
        case id
        case reposUrl = "repos_url"  // <-- here
    }
}

class NetworkingManager: ObservableObject{
    @Published var owner = [Owner]()
    
    init() {
        loadData()
    }
    
    func loadData() {
        guard let url = URL(string: "https://api.github.com/users/jacobtoye/repos") else { return }
        URLSession.shared.dataTask(with: url) {(data, _, _) in
            guard let data = data else { return }
            DispatchQueue.main.async { // <-- here
                do {
                    let repos = try JSONDecoder().decode([Repository].self, from: data)  // <-- here
                    repos.forEach{ self.owner.append($0.owner) }
                } catch {
                    print("error: \(error)")
                }
           }
        }.resume()
    }
}

struct ContentView: View {
    @StateObject var netManager = NetworkingManager()
    
    var body: some View {
        List {
            ForEach(netManager.owner) { item in
                Text(item.reposUrl)
            }
        }
    }
}

This should give you a list of "https://api.github.com/users/jacobtoye/repos" because that is what the data consist of.

EDIT-1: to list all repos

class NetworkingManager: ObservableObject{
    @Published var repos = [Repository]() // <-- here repos
    
    init() {
        loadData()
    }
    
    func loadData() {
        guard let url = URL(string: "https://api.github.com/users/jacobtoye/repos") else { return }
        URLSession.shared.dataTask(with: url) {(data, _, _) in
            guard let data = data else { return }
            DispatchQueue.main.async { // <-- here
                do {
                    self.repos = try JSONDecoder().decode([Repository].self, from: data)  // <-- here
                } catch {
                    print("error: \(error)")
                }
            }
        }.resume()
    }
}

struct ContentView: View {
    @StateObject var netManager = NetworkingManager()
    
    var body: some View {
        List {
            ForEach(netManager.repos) { repo in
              VStack {
                Text(repo.fullName).foregroundColor(.blue)
                Text(repo.owner.reposUrl)
              }
            }
        }
    }
}
我不是你的备胎 2025-01-30 03:45:29

在我最近的项目之后,一项小修正案在上面建议的解决方案中最好使用[弱自我],如果没有更多的参数在封闭中传递:

 guard let url = URL(string: "https://api.github.com/users/jacobtoye/repos") else { return }
    URLSession.shared.dataTask(with: url) { [weak self] (data, _, _) in
        guard let self = self, let data = data else { return }

而不是

guard let url = URL(string: "https://api.github.com/users/jacobtoye/repos") else { return }
        URLSession.shared.dataTask(with: url) {(data, _, _) in
            guard let data = data else { return }

通过这种方法,您可以防止内存泄漏,这可能会使您的记忆泄漏当一天结束时,应用程序较慢。

One small amendment, after my recent project, in the solution suggested above it is better to use [weak self] if no more parameters are passed in the closure:

 guard let url = URL(string: "https://api.github.com/users/jacobtoye/repos") else { return }
    URLSession.shared.dataTask(with: url) { [weak self] (data, _, _) in
        guard let self = self, let data = data else { return }

instead of

guard let url = URL(string: "https://api.github.com/users/jacobtoye/repos") else { return }
        URLSession.shared.dataTask(with: url) {(data, _, _) in
            guard let data = data else { return }

Thanks to that approach, you can prevent memory leak, which might make your app slower at the end of the day.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文