首页 > 解决方案 > 为什么我在 Swift 中的 JSON 代码无法解析?

问题描述

免责声明:以下非常基本的问题。我正在努力学习IOS开发的基础知识。

我目前正在尝试将数据从 API 解析到 SwiftUI 项目,但无法成功。

代码如下:

import SwiftUI

struct Poem: Codable {
    let title, author: String
    let lines: [String]
    let linecount: String
}

class FetchPoem: ObservableObject {
  // 1.
  @Published var poems = [Poem]()
     
    init() {
        let url = URL(string: "https://poetrydb.org/random/1")!
        // 2.
        URLSession.shared.dataTask(with: url) {(data, response, error) in
            do {
                if let poemData = data {
                    // 3.
                    let decodedData = try JSONDecoder().decode([Poem].self, from: poemData)
                    DispatchQueue.main.async {
                        self.poems = decodedData
                    }
                } else {
                    print("No data")
                }
            } catch {
                print("Error")
            }
        }.resume()
    }
}

struct ContentView: View {
        
    @ObservedObject var fetch = FetchPoem()
    
    let joined = fetch.poem.lines.joined(separator: "\n")
    
    var body: some View {
        Text(fetch.poem.title)
            .padding()
        Text( \(joined) )
            .padding()
    
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

当前构建失败。它向我抛出了以下错误:

Initializer 'init(_:)' requires that 'Binding<Subject>' conform to 'StringProtocol'

Referencing subscript 'subscript(dynamicMember:)' requires wrapper 'ObservedObject<FetchPoem>.Wrapper'

Value of type 'FetchPoem' has no dynamic member 'poem' using key path from root type 'FetchPoem'

此外,我试图将数组“Lines”附加到一个主字符串变量“Joined”中。但是,我不确定这是否有效......错误是“字符串插值只能出现在字符串文字中”。如果有人知道,希望得到一些帮助...

有任何想法吗?感谢所有帮助。


** 编辑代码 - Q2

import SwiftUI

struct Poem: Codable, Hashable {
    let title, author: String
    let lines: [String]
    let linecount: String
}

class FetchPoem: ObservableObject {

  @Published var poems = [Poem]()
     
    func getPoem() {
        let url = URL(string: "https://poetrydb.org/random/1")!
        // 2.
        URLSession.shared.dataTask(with: url) {(data, response, error) in
            do {
                if let poemData = data {
                    // 3.
                    let decodedData = try JSONDecoder().decode([Poem].self, from: poemData)
                    DispatchQueue.main.async {
                        self.poems = decodedData
                    }
                } else {
                    print("No data")
                }
            } catch {
                print("Error")
            }
        }.resume()
    }
}

struct ContentView: View {
        
    @ObservedObject var fetch = FetchPoem()
        
    var body: some View {
            VStack {
                if let poem = fetch.poems.first {
                    Button("Refresh") {getPoem}
                    Text("\(poem.author): \(poem.title)").bold()
                    Divider()
                    ScrollView {
                        VStack {
                            ForEach(poem.lines, id: \.self) {
                                Text($0)
                            }
                        }
                    }
                }
            }
        }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

标签: jsonswiftparsingswiftui

解决方案


很可能你想要这个(因为poems是一个数组) - 用 Xcode 12.1 / iOS 14.1 测试

struct Poem: Codable, Hashable {
    let title, author: String
    let lines: [String]
    let linecount: String
}

// ...

struct ContentView: View {
        
    @ObservedObject var fetch = FetchPoem()
    
    var body: some View {
        List {
            ForEach(fetch.poems, id: \.self) {
                Text("\($0.author): \($0.title)")
            }
        }
    }
}

... ,接下来可能会将其包装成NavigationView/NavigationLink在目的地视图中显示每首诗。

显示行如下:

var body: some View {
    VStack {
        if let poem = fetch.poems.first {
            Text("\(poem.author): \(poem.title)").bold()
            Divider()
            ScrollView {
                VStack {
                    ForEach(poem.lines, id: \.self) {
                        Text($0)
                    }
                }
            }
        }
    }
}

演示


推荐阅读