Skip to content
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Fx Studio
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Written by chuotfx on December 17, 2019

Basic iOS tutorial : Connect Networking

iOS & Swift

Contents

  • Chuẩn bị
  • 1. Bổ túc văn hoá
    • 1.1. Webservice & API
    • 1.2. Endpoint
    • 1.3. URL
    • 1.4. Query String
    • 1.5. Method
    • 1.6. Request
    • 1.7. Response
    • 1.8. JSON
  • 2. Mô hình
    • 2.1. Client Server
    • 2.2. Tương tác trong ứng dụng
  • 3. Hoạt động
    • 3.1. Create Request
    • 3.2. Connection
    • 3.3. Receive Response
    • 3.4. Parse data
    • 3.5. Networking Model
    • 3.6. Downloader
  • Tạm kết

Chào bạn đến với series Lập trình iOS cho mọi người. Nếu bạn là người theo dõi series này từ ngày đầu, thì các bài viết trước chỉ trong phạm vị của ứng dụng. Bài viết này sẽ vượt ra ngoài ứng dụng của bạn. Và chủ đề hôm nay sẽ là về Connect Networking trong iOS Project.

Để chuẩn bị cho bài này thì bạn cần phải nắm các kiến thức sau:

    • Closure trong 10 phút
    • Basic iOS tutorial : MVVM

Để sử tiết kiệm thời gian thì source code iOS Project, thì sẽ sử dụng lại của bài MVVM. Nếu bạn chưa nắm được kiến thức thì hãy quay lại các link trên để bổ túc. Còn nếu bạn đã sẵn sàng thì …

Bắt đầu thôi!

Chuẩn bị

  • MacOS 10.14.4
  • Xcode 11.0
  • Swift 5.1

1. Bổ túc văn hoá

Bạn là 1 lập trình viên chân chính, thì các kiến thức cơ bản về networking thì cũng phải nắm được. Sau đây, mình trình bày lại các khái niệm sẽ được dùng nhiều trong bài. Còn bạn muốn tìm hiểu kĩ về nó, thì có thể vài đường Google là ra. EZ Game!

1.1. Webservice & API

Web service là một hệ thống phần mềm được thiết kế để hỗ trợ khả năng tương tác giữa các ứng dụng trên các máy tính khác nhau thông qua mạng Internet, giao diện chung và sự gắn kết của nó được mô tả bằng XML. (theo W3C)

API (Application Programming Interface – Giao diện lập trình ứng dụng).

  • API là các hàm , phương thức để cho các ứng dụng bên ngoài có thể gọi , tương tác để trao đổi thông tin , tính toán.
  • Việc trao đổi này giúp các nhà lập trình tạo ra các service hỗ trợ những lập trình viên khác có thể tương tác với ứng dụng của chính mình
  • Hiện nay trên web các dịch vụ của google , facebook cung cấp rất nhiều api để lập trình viên có thể xây dựng tương tác giữa website của họ với google ,facebook

Web API

  • Khi đưa các API từ việc tương tác giữa các máy tình hay các phần mềm với nhau thành mô hình client / server thì mô hình Web API dần được hình thành.
  • Web API dùng phương thức trao đổi dữ liệu là HTTP , kiểu dữ liệu trao đổi là JSON , một chuẩn dữ liệu hướng đối tượng được dùng khá nhiều trong việc lưu chuyển thông tin trên Internet .
  • Tương tác với khá nhiều các nền tảng: mobile, web, pc, các hệ điều hành, các thiết bị ngoại vi…
  • RESTful đang là chuẩn phổ biến hiện nay.

1.2. Endpoint

Endpoint thực chất chính là URL: https://abc.com/foo/bar và lúc này ta gọi /foo/bar là Endpoint vì URL đằng trước thì giống nhau trong hầu hết các trường hợp.

1.3. URL

Uniform Resource Locator, dịch ra tiếng Việt là “Định vị Tài nguyên thống nhất” hay “Định vị Tài nguyên đồng dạng”. CLGT!

Đơn giản hơn “địa chỉ web”

Thành phần bao gồm:

  • Protocol: http, https, mailto
  • Domain
  • Port: 8088 , …
  • Path
  • Value

Ví dụ:  có 1 URL sau: https://www.google.com/maps/place?type=abc. Trong đó:

    • Protocol : https
    • Domain: www.google.com
    • Path: /map/place
    • Value: ?type=abc

1.4. Query String

  • Dùng để đọc dữ liệu do trang khác gửi tới thông qua phương thức GET
  • Thường là gửi dữ liệu bằng cách gắn vào ngay sau liên kết – URL.

Ví dụ: http://www.abc.com/TinhTuoi.php?NamSinh=1980

1.5. Method

  • Là phương thức mà HTTP Request này sử dụng.
  • Bao gồm:
    • GET
    • POST
    • HEAD
    • PUT
    • DELETE
    • OPTION
    • CONNECT

1.6. Request

Chứa các thông tin mà từ clien gởi lên server thông qua một connect được thiết lập.

Bao gồm:

  • Header : nơi chứa thông tin cấu hình và tính chất của Request  được gởi đi.
  • Body: nơi chưa dữ liệu cho request

1.7. Response

Là dữ liệu mà phía server gởi về client sau khi thực hiện 1 request. Cũng bao hồm Header & Body như request.

Tuỳ thuộc vào loại dữ liệu mà bạn có sử dụng thì chọn cách format chúng theo đúng như vậy. Công việc này người ta gọi là parse data.

1.8. JSON

  • JavaScript Object Notation (thường được viết tắt là JSON) là một kiểu dữ liệu mở trong JavaScript.
  • Kiểu dữ liệu này bao gồm chủ yếu là text, có thể đọc được theo dạng cặp “thuộc tính – giá trị”.
  • Về cấu trúc, nó mô tả một vật thể bằng cách bọc những vật thể con trong vật thể lớn hơn trong dấu ngoặc nhọn ({ }).
  • JSON là một kiểu dữ liệu trung gian, chủ yếu được dùng để vận chuyển thông tin giữa các thành phần của một chương trình

Ví dụ:

{
	"name":"Product",
	"properties":
	{
		"id":
		{
			"type":"number",
			"description":"Product identifier",
			"required":true
		},
		"name":
		{
			"description":"Name of the product",
			"type":"string",
			"required":true
		},
		"price":
		{
			"type":"number",
			"minimum":0,
			"required":true
		},
		"tags":
		{
			"type":"array",
			"items":
			{
				"type":"string"
			}
		}
	}
}

Trong iOS thì kiểu dữ liệu mô tả cho JSON là Dictionary với key là String và value là Any.

2. Mô hình

2.1. Client Server

Đây là mô hình siêu kinh điển trong lập trình.

  • Client mang nghĩa rộng. Có thể là thiết bị, người dùng, phần mềm …
  • Client luôn luôn là phía gởi request
  • Server là bên tiếp nhận request, xử lý thông tin và trả về response cho client

2.2. Tương tác trong ứng dụng

Sơ đồ trên là mô tả lại sự tương tác cơ bản trong ứng dụng. Chúng ta cần chú ý vài điểm như sau:

  • Để thực hiện bất cứ tương tác nào ra bên ngoài thì bạn cần nhớ điều đầu tiên là sử dụng 1 thread mới.
  • Tiếp theo là việc chờ đợi phản hồi từ Server.
  • Phân tích dữ liệu nhận được từ Server.
  • Đinh dạng lại dữ liệu cho đúng mục đích sử dụng.
  • Quay về Main Thread để cập nhật lại giao diện.

Về lý thuyết như vậy là ổn rồi. Tiến vào code thôi!

3. Hoạt động

Trước tiên thì bạn cần tìm 1 URL nào đó, có thể bất cứ cái nào cũng được. Hoặc sử dụng chính hàng của Apple như sau:

  • Rss Feed: http://rss.itunes.apple.com/en-us
  • Ví dụ: Hot Music từ iTunes : https://rss.itunes.apple.com/api/v1/us/itunes-music/hot-tracks/all/10/explicit.json

Về iOS Project thì:

  • Thêm 1 UITableView cho HomeViewController
  • Custom cell cho Tableview trên
  • Add thêm 1 UIBarButtonItem cho NavigationBar. Khi người dùng nhấn vào đó thì sẽ gọi function lấy dữ liệu từ URL trên.

File HomeViewController sẽ trông như thế này:

import UIKit

class HomeViewController: BaseViewController {
        
    @IBOutlet weak var tableview: UITableView!
    var viewmodel = HomeViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // MARK: - config
    override func setupUI() {
        super.setupUI()
        //title
        self.title = "Home"
        
        //tableview
        tableview.delegate = self
        tableview.dataSource = self
        
        let nib = UINib(nibName: "HomeCell", bundle: .main)
        tableview.register(nib, forCellReuseIdentifier: "cell")
        
        //navi
        let resetTabbarItem = UIBarButtonItem(image: UIImage(named: "ic-navi-refresh"), style: .plain, target: self, action: #selector(loadAPI))
        self.navigationItem.rightBarButtonItem = resetTabbarItem
    }
    
    override func setupData() {
    }
    
    func updateUI() {
        tableview.reloadData()
    }

    //MARK: - API
    @objc func loadAPI() {
        print("LOAD API")
    }
}

//MARK: - Tableview Delegate & Datasource
extension HomeViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        viewmodel.names.count
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        200
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HomeCell
        cell.titleLabel.text = viewmodel.names[indexPath.row]
        return cell
    }
}

Tiến sang ViewModel của nó là HomeViewModel. Chúng ta tiến hành cài đặt thêm một số thứ như sau:

  • Tạo ra 1 kiểu dữ liệu closure mới tên là Completion. Dùng làm call back cho các function của ViewModel.
    • Bool: thông báo việc load API có thành công hay không
    • String: chứa nội dụng cụ thể bị lỗi gì trong quá trình tương tác với API
  • 1 array String tên là names , để lưu các giá trị lấy được từ response.
import Foundation

typealias Completion = (Bool, String) -> Void

class HomeViewModel {
    var names: [String] = []
    
    func loadAPI(completion: @escaping Completion) {
        //chưa code gì hết nha.
    }
}

3.1. Create Request

Bắt đầu bằng việc gọi ViewModel thực thi yêu cầu từ Controller. Tại function loadAPI. Chúng ta sẽ gọi viewmodel tại đây:

@objc func loadAPI() {
        print("LOAD API")
        viewmodel.loadAPI { (done, msg) in
            if done {
                self.updateUI()
            } else {
                print("API ERROR: \(msg)")
            }
        }
    }

Nếu như việc tương tác thành công, thì sẽ gọi hàm updateUI để cập nhật lại giao diện. Nếu thất bại, thì in lỗi ra. Trong thực tế, bạn phải hiển thị ra alert, nhằm thông báo cho người dùng biết đang có lỗi. Còn bài này thì tạm thời mình bỏ qua nha!

Tại function loadAPI của HomeViewModel. Ta bắt đầu việc tạo request.

String URL ==> URL ==> Request

  • Bước 1: Biến đổi từ string của URL thành đối tượng URL
let urlString = "https://rss.itunes.apple.com/api/v1/us/itunes-music/hot-tracks/all/100/explicit.json"
let url = URL(string: urlString)
  • Bước 2: Tạo đối tượng Request từ đối tượng URL
let request = URLRequest(url: url!)
  • Bước 3: Nếu có thêm tham số hay cấu hình gì cho request thì thêm vào. Còn không thì có thể bỏ qua.
request.httpMethod = "GET"

Với một số API đơn giản, bạn có thể lượt bỏ đi request. Dùng trực tiếp đối tượng URL cho phần sau vẫn không sao.

3.2. Connection

Đây là phần chính. Với iOS thì bạn có rất nhiều cách, cũng như rất nhiều thư viện phục vụ việc tương tác với API. Trong bài này chúng ta sử dụng URLSession.

  • Đầu tiên tạo cấu hình cho Session
let config = URLSessionConfiguration.ephemeral
config.waitsForConnectivity = true
  • Tạo đối tượng URLSession từ cấu hình trên
let session = URLSession(configuration: config)
  • Tạo 1 URLSessionDataTask từ session và request. Ở đây nó sẽ chưa thực thi, chỉ mang tính chất setup chuẩn bị cho việc connect.
let task = session.dataTask(with: request) { (data, response, error) in
            DispatchQueue.main.async {
                if let error = error {
                    print("API - THẤT BẠI")
                } else {
                    print("API - THÀNH CÔNG")
                }
            }
        }

Việc tương tác này là bất đồng bộ.

Nên khi setup dataTast, ta thấy có 1 closure nhận về. Trong đó:

    • data là dữ liệu ở dạng nhị phân. Tức mãng bytes hay kiểu dữ liệu của nó iOS là Data
    • response chứa thông tin của response trả về. Bạn có thể lấy được status_code, để biết là thành công hay không.
    • error là lỗi. Nếu có lỗi phát sinh thì error sẽ khác nil.

Vì công việc thực thi là bất đồng bộ, khi bạn muốn cập nhật lại giao diện thì phải về lại Main Thread. Nên phải sử dụng tới DispatchQueue. Còn nếu bạn quên mất kiến thức về DispatchQueue hay GCD thì tham khảo các bài viết về nó trong Fx Studio.

  • Cuối cùng là việc thực thi connect. Sử dụng hàm resume của Task.
task.resume()

Tới đây, thì bạn nên build và test project của bạn có hoạt động đúng như mong muốn chưa. Nếu oke rồi thì chúng ta sẽ tiến qua phần xử lý response.

3.3. Receive Response

Dữ liệu nhân được từ việc phản hồi của Server là các mã nhị phân. Hay kiểu dữ liệu trong iOS đó là Data.

Công việc chính trong phần này chính là biến đổi dữ liệu. Vì từ Data bạn có thể biến đổi thành

  • Text
  • HTML
  • XML
  • JSON
  • Image
  • Video
  • Audio
  • …

Trong bài chúng ta sẽ biến đổi nó về JSON. Để tiện lợi thì chúng ta lại viết thêm một extension cho lớp Data. Tạo 1 file swift với tên là Data.Ext.swift. Trong đó:

  • Định nghĩa kiểu JSON, bằng cách định danh lại Dictionary
  • Thêm 1 function cho lớp Data
import Foundation

typealias JSON = [String: Any]

extension Data {
    func toJSON() -> JSON {
        var json: [String: Any] = [:]
        do {
            if let jsonObj = try JSONSerialization.jsonObject(with: self, options: .mutableContainers) as? JSON {
                json = jsonObj
            }
        } catch {
            print("JSON casting error")
        }
        return json
    }
}

Quay về với file HomeViewModel. Tiến hành việc phân tích closure nhận được từ Server

let task = session.dataTask(with: request) { (data, response, error) in
            DispatchQueue.main.async {
                if let error = error {
                    //call back
                    completion(false, error.localizedDescription)
                } else {
                    if let data = data {
                        let json = data.toJSON()
                        
                        //call back
                        completion(true, "")
                    } else {
                       //call back
                       completion(false, "Data format is error.")
                    }
                }
            }
        }

Ta thay các print bằng việc gọi closure của hàm loadAPI. Nếu

  • Thành công thì Bool là true và String là rỗng
  • Thất bại thì Bool là false và String là chuỗi string

Khi nhận được response thì việc đầu tiên là kiểm tra xem error != nil hay không. Để xác định việc tương tác thành công hay là lỗi.

Error là 1 optional.

Tiếp theo, nếu vào trường hợp thành công thì bạn cần phải kiểm tra tiếp là data của bạn có tồn tại hay không. Vì 2 việc này cũng không liên quan với nhau lắm.

Đôi khi thành công trong việc connect và nhận được response. Nhưng dữ liệu bị lỗi thì vẫn xãy ra. Và data cũng là 1 optional.

Cuối cùng là call back cho ViewController biết tình hình như thế nào. Thông qua việc gọi các completion.

3.4. Parse data

Công việc này chính là phân tích JSON để lấy được giá trị mong muốn.

Kiểm tra JSON trên trình duyệt web và ngồi suy luận một tí.

  • feed chứa toàn bộ thông tin. Nó là 1 JSON
  • results , nó ở trong feed. Và nó là một Array JSON. Nó chứa các phần tử mình cần.
  • Trong mỗi phần tử, ta thấy name . Nó chính là cái tên mình cần sử dụng để hiển thị lên TableView.

Tiến hành chuyển đổi qua code Swift. Ta được:

let json = data.toJSON()
let feed = json["feed"] as! JSON
let results = feed["results"] as! [JSON]

results là một mãng. Nên tiếp tục for để duyệt từng phần tử trong đó. Và lấy giá trị của name ra. Thêm nó vào array names của ViewModel. Nhằm lưu trữ dữ liệu cho View.

for item in results {
    let name = item["name"] as! String
    self.names.append(name)
}

Xem lại toàn bộ code của function loadAPI tại HomeViewModel.

func loadAPI(completion: @escaping Completion) {
        //create request
        let urlString = "https://rss.itunes.apple.com/api/v1/us/itunes-music/hot-tracks/all/100/explicit.json"
        let url = URL(string: urlString)
        var request = URLRequest(url: url!)
        request.httpMethod = "GET"
        
        //config
        let config = URLSessionConfiguration.ephemeral
        config.waitsForConnectivity = true

        //session
        let session = URLSession(configuration: config)
        
        //connect
        let task = session.dataTask(with: request) { (data, response, error) in
            DispatchQueue.main.async {
                if let error = error {
                    completion(false, error.localizedDescription)
                } else {
                    if let data = data {
                        let json = data.toJSON()
                        let feed = json["feed"] as! JSON
                        let results = feed["results"] as! [JSON]
                        
                        for item in results {
                            let name = item["name"] as! String
                            self.names.append(name)
                        }
                        
                        completion(true, "")
                    } else {
                       completion(false, "Data format is error.")
                    }
                }
            }
        }
            
        task.resume()
        print("DONE")
    }

Build và cảm nhận kết quả.

3.5. Networking Model

Tất nhiên, chúng ta sẽ không phải ngồi code 1 đống code cho mỗi lần tương tác với API. Để tiết kiện thời gian, chúng ta cần phải tạo ra Model riêng để sử dụng. Và nó phải bao quát nhiều nhất các trường hợp tương tác có thể nhất.

Tạo class cho đối tượng cần parse. New 1 file mới tên là Music.  Trong này:

  • Các properties là các dữ liệu chúng ta cần cho việc hiển thị
  • Khởi tạo đối tượng từ một JSON.
import Foundation
import UIKit

final class Music {
    var id: String
    var artistName: String
    var releaseDate: String
    var name: String
    var artworkUrl100: String
    var thumbnailImage: UIImage?
    
    init(json: JSON) {
        self.id = json["id"] as! String
        self.artistName = json["artistName"] as! String
        self.releaseDate = json["releaseDate"] as! String
        self.name = json["name"] as! String
        self.artworkUrl100 = json["artworkUrl100"] as! String
    }
}

Custom lại một enum để phục vụ cho Error. Cái này tạm thời bạn chỉ cần sử dụng là được rồi. Vì:

  • Error, của hệ thống là một Protocol. Nên nếu muốn dùng thì bạn sẽ cần phải kế thừa lại nó.
  • Sử dụng enum, để đơn giản hoá việc xử lí các error. Có thời gian mình sẽ trình bày nó riêng một chủ đề khác.
enum APIError: Error {
    case error(String)
    case errorURL
    
    var localizedDescription: String {
        switch self {
        case .error(let string):
            return string
        case .errorURL:
            return "URL String is error."
        }
    }
}

Tạo mới một class tên là Networking.  Áp dụng singleton vào class này.

import Foundation

final class Networking {
    //MARK: - singleton
    private static var sharedNetworking: Networking = {
        let networking = Networking()
        return networking
    }()
    
    class func shared() -> Networking {
        return sharedNetworking
    }
    
    //MARK: - init
    private init() {}
    
    //MARK: - request

    //MARK: - downloader
    
}

Viết một function mới cho việc request . Với

  • urlString là tham số cho link request
  • completion là closure cho call back.
  • Chỉ trả về data và error kiểu Optional
func request(with urlString: String, completion: @escaping (Data?, APIError?) -> Void) {
   // code sau nha 
}

Move code hay viết lại code của phần tương tác với Server tương tự như trên.

func request(with urlString: String, completion: @escaping (Data?, APIError?) -> Void) {
        guard let url = URL(string: urlString) else {
            let error = APIError.error("URL lỗi")
            completion(nil, error)
            return
        }
        
        let config = URLSessionConfiguration.ephemeral
        config.waitsForConnectivity = true
        
        let session = URLSession(configuration: config)
        let task = session.dataTask(with: url) { (data, response, error) in
            DispatchQueue.main.async {
                if let error = error {
                    completion(nil, APIError.error(error.localizedDescription))
                } else {
                    if let data = data {
                        completion(data, nil)
                    } else {
                       completion(nil, APIError.error("Data format is error."))
                    }
                }
            }
        }
        task.resume()
    }

Mở file HomeViewModel tiến hành thay đổi một số điểm sau:

  • Tạo 1 array với đối tượng Music
var musics: [Music] = []
  • Viết lại function loadAPI, sử dụng model vừa tạo. Tạm thời đặt tên nó là loadAPI2(cho khỏi trùng tên)
func loadAPI2(completion: @escaping Completion) {
        let urlString = "https://rss.itunes.apple.com/api/v1/us/itunes-music/hot-tracks/all/100/explicit.json"
        
        Networking.shared().request(with: urlString) { (data, error) in
            if let error = error {
                completion(false, error.localizedDescription)
            } else {
                if let data = data {
                    let json = data.toJSON()
                    let feed = json["feed"] as! JSON
                    let results = feed["results"] as! [JSON]
                    
                    for item in results {
                        let music = Music(json: item)
                        self.musics.append(music)
                        
                        completion(true, "")
                    }
                } else {
                    completion(false, "Data format is error.")
                }
            }
        }
    }

Mở file HomeViewController và update lại phần delegate & datasource của TableView với dữ liệu là đối tượng Music. Tiến hành build và cảm nhận kết quả. Tham khảo code như sau:

extension HomeViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        viewmodel.musics.count
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        200
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HomeCell
        
        let item = viewmodel.musics[indexPath.row]
        cell.titleLabel.text = item.name
        cell.artistNameLabel.text = item.artistName

        return cell
    }
}

Dữ liệu đã có cho title bài nhạc và tên tác giả. Nhưng thiếu đi phần hình ảnh. Tiếp tục chuyển sang phần hình ảnh.

3.6. Downloader

Downloader chính là công việc tương tác với API. Nhưng thay vì format dữ liệu thành JSON, thì chúng ta biến nó thành UIImage.

Mở file Networking, tiến hành clone lại function request. Nhưng thay đổi để phù hợp việc biến đổi thành UIImage.

  • Chú ý việc biển đổi Data thành UIImage
    • Xem tham số completion
  • let image = UIImage(data: data)
func downloadImage(url: String, completion: @escaping (UIImage?) -> Void) {
        guard let url = URL(string: url) else {
            completion(nil)
            return
        }
        let config = URLSessionConfiguration.default
        config.waitsForConnectivity = true
        let session = URLSession(configuration: config)
        let task = session.dataTask(with: url) { (data, response, error) in
            DispatchQueue.main.async {
                if let _ = error {
                    completion(nil)
                } else {
                    if let data = data {
                        let image = UIImage(data: data)
                        completion(image)
                    } else {
                        completion(nil)
                    }
                }
            }
        }
        task.resume()
    }

Tiến hành download image cho cell của TableView. Tại hàm cell For Row, tiến hành edit đoạn code sau:

  • Cứ mỗi lần chạy qua từng row. Thì sẽ lấy được thứ tự của item trong array bằng indexPath
  • Kiểm tra item có image chưa. Nếu chưa thì tiến hành gọi download.
  • Nhận được image thì cập nhật lại cho cell và item.
 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HomeCell
        
        let item = viewmodel.musics[indexPath.row]
        cell.titleLabel.text = item.name
        cell.artistNameLabel.text = item.artistName
        
        if item.thumbnailImage != nil {
            cell.thumbnail.image = item.thumbnailImage
        } else {
            cell.thumbnail.image = nil
            
            //downloader
            Networking.shared().downloadImage(url: item.artworkUrl100) { (image) in
                if let image = image {
                    cell.thumbnail.image = image
                    item.thumbnailImage = image
                } else {
                    cell.thumbnail.image = nil
                }
            }
        }
        
        return cell
    }

Cần chú ý khi làm việc với TableView,  điều quan trọng là có if thì phải có else. Nên cần việc quản lý các trường hợp, lỗi và không có ảnh. Thì phải xét ảnh của cell là nil.

Nếu thành công, bạn cần cập nhật lại ảnh cho đối tượng Music, để không cần gọi request lấy ảnh từ Server nữa. Build và cảm nhận kết quả.

Okay, giờ thì bạn đã có đủ skill để giết hết các yêu cầu liên quan tới tương tác networking. Ngoài ra, còn bổ sung thêm kiến thức downloader để download image cho cell của TableView rồi. Bạn có thể checkout mã nguồn tại đây. Chúc bạn thành công!

Tạm kết

  • Các khái niệm dùng trong Networking
  • Mô hình cho việc tương tác
  • Sự hoạt động của URLSession và các đàn em của nó
  • Parser Data
  • Download image cho cell của TableView

Cảm ơn bạn đã đọc bài viết này!

 

FacebookTweetPinYummlyLinkedInPrintEmailShares37

Related Posts:

  • RxCocoa Basic – Binding Observables
    RxCocoa Basic – Binding Observables
  • RxCocoa Basic – Delegate Proxy
    RxCocoa Basic – Delegate Proxy
  • RxCocoa Basic - Display Data
    RxCocoa Basic - Display Data
  • RxSwift vs. UIKit – Networking
    RxSwift vs. UIKit – Networking
Tags: api, basic ios tutorial, iOS
Written by chuotfx

Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Donate – Buy me a coffee!

Fan page

Fx Studio

Tags

Actor Advanced Swift api AppDistribution Asynchronous autolayout basic ios tutorial blog callback ci/cd closure collectionview combine concurrency CoreData Core Location crashlytics darkmode dart dart basic dart tour Declarative decoding delegate deploy fabric fastlane firebase flavor flutter GCD iOS mapview MVVM optional protocol rxswift Swift Swift 5.5 SwiftUI SwiftUI Notes tableview testing TravisCI unittest

Recent Posts

  • Raw String trong 10 phút
  • Dispatch Semaphore trong 10 phút
  • Tổng kết năm 2022
  • KeyPath trong 10 phút – Swift
  • Make color App Flutter
  • Ứng dụng Flutter đầu tiên
  • Cài đặt Flutter SDK & Hello world
  • Coding Conventions – người hùng hay kẻ tội đồ?
  • Giới thiệu về Flutter
  • Tìm hiểu về ngôn ngữ lập trình Dart

You may also like:

  • RxCocoa Basic – Forward Delegate
    RxCocoa Basic – Forward Delegate
  • SwiftUI - Phần 6 : Basic UI Controls
    SwiftUI - Phần 6 : Basic UI Controls
  • RxCocoa Basic – Display Data from API
    RxCocoa Basic – Display Data from API
  • RxCocoa Basic – Delegate Proxy
    RxCocoa Basic – Delegate Proxy
  • Display a basic TableView - RxSwift
    Display a basic TableView - RxSwift

Archives

  • February 2023 (1)
  • January 2023 (2)
  • November 2022 (2)
  • October 2022 (1)
  • September 2022 (5)
  • August 2022 (6)
  • July 2022 (7)
  • June 2022 (8)
  • May 2022 (5)
  • April 2022 (1)
  • March 2022 (3)
  • February 2022 (5)
  • January 2022 (4)
  • December 2021 (6)
  • November 2021 (8)
  • October 2021 (8)
  • September 2021 (8)
  • August 2021 (8)
  • July 2021 (9)
  • June 2021 (8)
  • May 2021 (7)
  • April 2021 (11)
  • March 2021 (12)
  • February 2021 (3)
  • January 2021 (3)
  • December 2020 (3)
  • November 2020 (9)
  • October 2020 (7)
  • September 2020 (17)
  • August 2020 (1)
  • July 2020 (3)
  • June 2020 (1)
  • May 2020 (2)
  • April 2020 (3)
  • March 2020 (20)
  • February 2020 (5)
  • January 2020 (2)
  • December 2019 (12)
  • November 2019 (12)
  • October 2019 (19)
  • September 2019 (17)
  • August 2019 (10)

About me

Education, Mini Game, Digital Art & Life of coders
Contacts:
contacts@fxstudio.dev

Fx Studio

  • Home
  • About me
  • Contact us
  • Mail
  • Privacy Policy
  • Donate
  • Sitemap

Categories

  • Art (1)
  • Blog (22)
  • Code (4)
  • Combine (22)
  • Flutter & Dart (24)
  • iOS & Swift (86)
  • RxSwift (37)
  • SwiftUI (76)
  • Tutorials (70)

Newsletter

Stay up to date with our latest news and posts.
Loading

    Copyright © 2023 Fx Studio - All rights reserved.

    Share this ArticleLike this article? Email it to a friend!

    Email sent!