نمایش لیست با 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 مانند تصویر زیر نمایش دهیم:
ابتدا باید مدلی برای 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}
به این صورت به پایان این راهنما میرسیم.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی
- آموزش برنامه نویسی Swift (سوئیفت) برای برنامه نویسی iOS
- مجموعه آموزشهای دروس علوم و مهندسی کامپیوتر
- ساخت اپلیکیشن با Firebase و SwiftUI — از صفر تا صد
- ساخت کنترل Overlay تعاملی با SwiftUI — از صفر تا صد
==