نمایش لیست با SwiftUI و داده های فایل JSON ریموت — از صفر تا صد

۴۵ بازدید
آخرین به‌روزرسانی: ۱۸ شهریور ۱۴۰۲
زمان مطالعه: ۳ دقیقه
نمایش لیست با SwiftUI و داده های فایل JSON ریموت — از صفر تا صد

هدف این مقاله نمایش یک روش ساده برای واکشی کردن داده‌ها از یک فایل JSON ریموت و نمایش لیست با SwiftUI است. روشی که در این مقاله معرفی می‌شود، برای به‌کارگیری در نسخه جدید Xcode 11 (11A420a) مناسب است.

کتابخانه‌های بتای اپل به طور مداوم پیش از انتشار نسخه‌های نهایی در حال تغییر هستند و از این رو ممکن است راهنماهای قدیمی در جدیدترین نسخه‌های Xcode کار نکنند.

فرض کنید فایل JSON زیر را که حاوی آرایه‌ای از عناوین فیلم‌ها است در اختیار داریم.

1[{
2	"id": 5,
3	"title": "Joker",
4	"year": "2019",
5	"image": "",
6	"created_at": "2019-10-06T17:55:21.374Z",
7	"updated_at": "2019-10-06T17:55:21.374Z"
8}, {
9	"id": 1,
10	"title": "Pulp Fiction",
11	"year": "1994",
12	"image": "",
13	"created_at": "2019-10-06T15:26:36.675Z",
14	"updated_at": "2019-10-06T18:05:31.649Z"
15}, {
16	"id": 4,
17	"title": " The Godfather ",
18	"year": "1972",
19	"image": "",
20	"created_at": "2019-10-06T15:27:38.123Z",
21	"updated_at": "2019-10-06T18:05:50.242Z"
22}, {
23	"id": 6,
24	"title": "The Dark Knight ",
25	"year": "2008",
26	"image": "",
27	"created_at": "2019-10-06T18:06:12.933Z",
28	"updated_at": "2019-10-06T18:06:12.933Z"
29}, {
30	"id": 7,
31	"title": "Fight Club",
32	"year": "1999",
33	"image": "",
34	"created_at": "2019-10-06T18:06:33.096Z",
35	"updated_at": "2019-10-06T18:06:33.096Z"
36}, {
37	"id": 8,
38	"title": " Inception",
39	"year": "2010",
40	"image": "",
41	"created_at": "2019-10-06T18:06:52.034Z",
42	"updated_at": "2019-10-06T18:06:52.034Z"
43}, {
44	"id": 2,
45	"title": "The Matrix ",
46	"year": "1999",
47	"image": "",
48	"created_at": "2019-10-06T15:26:48.042Z",
49	"updated_at": "2019-10-06T18:08:00.902Z"
50}, {
51	"id": 3,
52	"title": "The Shawshank Redemption ",
53	"year": "1984",
54	"image": "",
55	"created_at": "2019-10-06T15:26:59.572Z",
56	"updated_at": "2019-10-06T18:08:47.637Z"
57}]

ما می‌خواهیم آن‌ها را روی یک لیست SwiftUI مانند تصویر زیر نمایش دهیم:

نمایش لیست با SwiftUI

ابتدا باید مدلی برای Movie تعریف کنیم که در این مورد یک struct با پروتکل‌های Decodable و Identifiable است. Decodable می‌تواند آن را از فایل JSON دیکد کند و Identifiable می‌تواند در یک لیست آن‌ها را فهرست‌بندی کند. List امکان فهرست‌بندی داده‌های به دست آمده از کلکسیون Identifiable را مانند یک UITableViewController فراهم می‌سازد.

1struct Movie: Decodable, Identifiable {
2    public var id: Int
3    public var name: String
4    public var released: String
5    
6    enum CodingKeys: String, CodingKey {
7           case id = "id"
8           case name = "title"
9           case released = "year"
10        }
11}

CodingKeys اساساً نام‌های کلید JSON را به نام متغیر Model که ایجاد کردیم نگاشت می‌کند. در این مورد به جای year آن را released می‌نامیم و تنها منظورمان این است که نشان دهیم تا زمانی که نام‌های انتخابی خودتان را در Coding Keys تعریف می‌کنید، می‌توانید از آن‌ها به این مقصود بهره بگیرید.

سپس کلاس واکشی کننده (fetcher) را ایجاد می‌کنیم که فایل JSON را بارگذاری کرده و آن را دیکد می‌کند.

1public class MovieFetcher: ObservableObject {
2    @Published var movies = [Movie]()
3    
4    init(){
5        load()
6    }
7    
8    func load() {
9        let url = URL(string: "https://gist.githubusercontent.com/rbreve/60eb5f6fe49d5f019d0c39d71cb8388d/raw/f6bc27e3e637257e2f75c278520709dd20b1e089/movies.json")!
10    
11        URLSession.shared.dataTask(with: url) {(data,response,error) in
12            do {
13                if let d = data {
14                    let decodedLists = try JSONDecoder().decode([Movie].self, from: d)
15                    DispatchQueue.main.async {
16                        self.movies = decodedLists
17                    }
18                }else {
19                    print("No Data")
20                }
21            } catch {
22                print ("Error")
23            }
24            
25        }.resume()
26         
27    }
28}

پیش از درک این که چه اتفاقاتی در حال رخ دادن است، باید فریمورک جدید Combine را درک کنیم.

فریمورک Combine یک API اعلانی سوئیفت برای پردازش مقادیر در طی زمان ارائه می‌دهد. این مقادیر می‌توانند انواع زیادی از رویدادهای ناهمگام را نمایندگی کنند. Combine اقدام به اعلان ناشران (publisher-ها) برای افشای مقادیری که ممکن است در طی زمان تغییر یابند کرده است و همچنین مشترکان (subscribers) را اعلان کرده است که آن مقادیر را از ناشران دریافت می‌کنند.

ObervableObject نوعی از شیء است که یک ناشر پیش از تغییر یافتن شیء انتشار می‌دهد. به صورت پیش‌فرض یک ObservableObject اقدام به تولید یک objectWillChange برای ناشر می‌کند که مقدار تغییریافته را پیش از هر گونه تغییر مشخصه Published@ صادر می‌کند.

Published@ پیرامون آرایه movies پوششی ایجاد می‌کند و هر زمان که تغییر یابد، رویدادهایی می‌سازد. متد ()load داده‌های JSON را به صورت ناهمگام از شبکه می‌گیرد و زمانی که داده‌ها بارگذاری شدند، آن‌ها را به movies انتساب می‌دهیم. هنگامی که moves تغییر یابد یک رویداد به مشترک ارسال می‌کند.

در ادامه یک نما-(view)-ی SwiftUI را می‌بینید که یک List با واکشی کننده ObservedObject به عنوان پارامتر دارد و هر زمان که movies به‌روزرسانی شود، این لیست هم به صورت خودکار به‌روزرسانی خواهد شد.

1struct ContentView: View {
2    @ObservedObject var fetcher = MovieFetcher()
3    
4    var body: some View {
5        VStack {
6            List(fetcher.movies) { movie in
7                VStack (alignment: .leading) {
8                    Text(movie.name)
9                    Text(movie.released)
10                        .font(.system(size: 11))
11                        .foregroundColor(Color.gray)
12                }
13            }
14        }
15    }
16}

کد کامل به صورت زیر است:

1//
2//  FetchView.swift
3//
4//  Created by Roberto Breve  on 4.10.2019.
5//  Copyright © 2019 Roberto Breve . All rights reserved.
6//
7import Foundation
8import SwiftUI
9import Combine
10 
11
12struct FetchView: View {
13    @ObservedObject var fetcher = MovieFetcher()
14    
15    var body: some View {
16        VStack {
17            List(fetcher.movies) { movie in
18                VStack (alignment: .leading) {
19                    Text(movie.name)
20                    Text(movie.released)
21                        .font(.system(size: 11))
22                        .foregroundColor(Color.gray)
23                }
24            }
25        }
26    }
27}
28
29 
30
31public class MovieFetcher: ObservableObject {
32
33    @Published var movies = [Movie]()
34    
35    init(){
36        load()
37    }
38    
39    func load() {
40        let url = URL(string: "https://gist.githubusercontent.com/rbreve/60eb5f6fe49d5f019d0c39d71cb8388d/raw/f6bc27e3e637257e2f75c278520709dd20b1e089/movies.json")!
41    
42        URLSession.shared.dataTask(with: url) {(data,response,error) in
43            do {
44                if let d = data {
45                    let decodedLists = try JSONDecoder().decode([Movie].self, from: d)
46                    DispatchQueue.main.async {
47                        self.movies = decodedLists
48                    }
49                }else {
50                    print("No Data")
51                }
52            } catch {
53                print ("Error")
54            }
55            
56        }.resume()
57         
58    }
59}
60
61struct Movie: Codable, Identifiable {
62    public var id: Int
63    public var name: String
64    public var released: String
65    
66    enum CodingKeys: String, CodingKey {
67           case id = "id"
68           case name = "title"
69           case released = "year"
70        }
71}

به این صورت به پایان این راهنما می‌رسیم.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۱ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
rbreve
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *