"Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil; GitHub repo showing app; SwiftUI
"Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil; GitHub repo showing app; SwiftUI
我需要创建一个能够 return GitHub 用户拥有的所有存储库的应用程序。
我创建了一个包含 3 个文件的应用程序:
内容视图
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
}
DECODERS(因为我知道我以后需要另一个,除非我能足够抽象这个)
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 被包装在常量中时,我不知道如何把它放在那里。
对于极简主义的工作示例代码,试试这个:
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([=10=].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"
的列表,因为这是数据的组成部分。
EDIT-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)
}
}
}
}
}
一个小修改,在我最近的项目之后,在上面建议的解决方案中,如果闭包中没有传递更多参数,则更好地使用[weak self]:
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 }
由于这种方法,您可以防止内存泄漏,这可能会使您的应用在一天结束时变慢。
我需要创建一个能够 return GitHub 用户拥有的所有存储库的应用程序。
我创建了一个包含 3 个文件的应用程序: 内容视图
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
}
DECODERS(因为我知道我以后需要另一个,除非我能足够抽象这个)
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 被包装在常量中时,我不知道如何把它放在那里。
对于极简主义的工作示例代码,试试这个:
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([=10=].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"
的列表,因为这是数据的组成部分。
EDIT-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)
}
}
}
}
}
一个小修改,在我最近的项目之后,在上面建议的解决方案中,如果闭包中没有传递更多参数,则更好地使用[weak self]:
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 }
由于这种方法,您可以防止内存泄漏,这可能会使您的应用在一天结束时变慢。