SwiftUI 中级之List显示远程Json文件(2020年教程)

SwiftUI 中级之List显示远程Json文件(2020年教程)

本文的目的是展示一种从远程JSON文件获取数据并将其显示在SwiftUI中的列表上的简单方法。

数据介绍

下面是我们json文件的格式

[{
    "id": 5,
    "title": "Joker",
    "year": "2019",
    "image": "",
    "created_at": "2019-10-06T17:55:21.374Z",
    "updated_at": "2019-10-06T17:55:21.374Z"
}, {
    "id": 1,
    "title": "Pulp Fiction",
    "year": "1994",
    "image": "",
    "created_at": "2019-10-06T15:26:36.675Z",
    "updated_at": "2019-10-06T18:05:31.649Z"
}, {
    "id": 4,
    "title": " The Godfather ",
    "year": "1972",
    "image": "",
    "created_at": "2019-10-06T15:27:38.123Z",
    "updated_at": "2019-10-06T18:05:50.242Z"
}, {
    "id": 6,
    "title": "The Dark Knight ",
    "year": "2008",
    "image": "",
    "created_at": "2019-10-06T18:06:12.933Z",
    "updated_at": "2019-10-06T18:06:12.933Z"
}, {
    "id": 7,
    "title": "Fight Club",
    "year": "1999",
    "image": "",
    "created_at": "2019-10-06T18:06:33.096Z",
    "updated_at": "2019-10-06T18:06:33.096Z"
}, {
    "id": 8,
    "title": " Inception",
    "year": "2010",
    "image": "",
    "created_at": "2019-10-06T18:06:52.034Z",
    "updated_at": "2019-10-06T18:06:52.034Z"
}, {
    "id": 2,
    "title": "The Matrix ",
    "year": "1999",
    "image": "",
    "created_at": "2019-10-06T15:26:48.042Z",
    "updated_at": "2019-10-06T18:08:00.902Z"
}, {
    "id": 3,
    "title": "The Shawshank Redemption ",
    "year": "1984",
    "image": "",
    "created_at": "2019-10-06T15:26:59.572Z",
    "updated_at": "2019-10-06T18:08:47.637Z"
}]

预期效果

编码

首先,我们需要为Movie定义模型,在这种情况下,该模型是具有Decodable和Identifiable协议的struct。Decodable能够从JSON文件中对其进行解码,Identifiable能够与List一起列出。List可以像UITableViewController一样显示可标识集合中的数据列表。

struct Movie: Decodable, Identifiable {
    public var id: Int
    public var name: String
    public var released: String
    
    enum CodingKeys: String, CodingKey {
           case id = "id"
           case name = "title"
           case released = "year"
        }
}

CodingKeys能够将JSON key名称与您创建的Model的变量名称进行映射。在这种情况下,我将其命名为Release而不是年份,只是为了表明您可以在模型中使用自己的名称,只要您在Coding Keys中定义它即可。

下面我们将编码读取数据并进行解码的代码

public class MovieFetcher: ObservableObject {
    @Published var movies = [Movie]()
    
    init(){
        load()
    }
    
    func load() {
        let url = URL(string: "https://gist.githubusercontent.com/rbreve/60eb5f6fe49d5f019d0c39d71cb8388d/raw/f6bc27e3e637257e2f75c278520709dd20b1e089/movies.json")!
    
        URLSession.shared.dataTask(with: url) {(data,response,error) in
            do {
                if let d = data {
                    let decodedLists = try JSONDecoder().decode([Movie].self, from: d)
                    DispatchQueue.main.async {
                        self.movies = decodedLists
                    }
                }else {
                    print("No Data")
                }
            } catch {
                print ("Error")
            }
            
        }.resume()
         
    }
}

Combine框架提供了一个声明性的Swift API,用于随时间处理值。这些值可以表示多种异步事件。 Combine声明发布者公开随时间变化的值,订阅者从发布者那里接收这些值。
@ObervableObject:具有发布者功能的一种对象,该对象在对象更改之前发出。默认情况下,@ObservableObject会合成一个objectWillChange发布者,该发布者会在其@Published属性中的任何一个发生更改之前发出更改的值。
@Published修饰movies数组后,当movies发生改变是将通知所有的ObserableObject。

load()方法从网络异步获取JSON数据,一旦数据加载完毕,我们便将其分配给movie数组。movie数组更改时,它将向订户发送事件。

struct ContentView: View {
    @ObservedObject var fetcher = MovieFetcher()
    
    var body: some View {
        VStack {
            List(fetcher.movies) { movie in
                VStack (alignment: .leading) {
                    Text(movie.name)
                    Text(movie.released)
                        .font(.system(size: 11))
                        .foregroundColor(Color.gray)
                }
            }
        }
    }
}

完整代码


import Foundation
import SwiftUI
import Combine
 
public class MovieFetcher: ObservableObject {

    @Published var movies = [Movie]()
    
    init(){
        load()
    }
    
    func load() {
        let url = URL(string: "https://gist.githubusercontent.com/rbreve/60eb5f6fe49d5f019d0c39d71cb8388d/raw/f6bc27e3e637257e2f75c278520709dd20b1e089/movies.json")!
    
        URLSession.shared.dataTask(with: url) {(data,response,error) in
            do {
                if let d = data {
                    let decodedLists = try JSONDecoder().decode([Movie].self, from: d)
                    DispatchQueue.main.async {
                        self.movies = decodedLists
                    }
                }else {
                    print("No Data")
                }
            } catch {
                print ("Error")
            }
            
        }.resume()
         
    }
}

struct Movie: Codable, Identifiable {
    public var id: Int
    public var name: String
    public var released: String
    
    enum CodingKeys: String, CodingKey {
           case id = "id"
           case name = "title"
           case released = "year"
        }
}


struct ListJsonView: View {
    @ObservedObject var fetcher = MovieFetcher()
    
    var body: some View {
        VStack {
            List(fetcher.movies) { movie in
                VStack (alignment: .leading) {
                    Text(movie.name)
                    Text(movie.released)
                        .font(.system(size: 11))
                        .foregroundColor(Color.gray)
                }
            }
        }
    }
}

 


struct ListJsonView__Previews: PreviewProvider {
    static var previews: some View {
        ListJsonView()
    }
}

参考文件

  • https://medium.com/@rbreve/displaying-a-list-with-swiftui-from-a-remote-json-file-6b4e4280a076

更多SwiftUI教程和代码关注专栏

  • 请关注我的专栏 SwiftUI教程与源码

你可能感兴趣的:(SwiftUI 中级之List显示远程Json文件(2020年教程))