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 October 4, 2020

RxSwift vs. UIKit – Hello ViewController

RxSwift

Contents

  • Chuẩn bị
  • 1. RxSwift vs. UIKit
  • 2. Setup
    • 2.1. Project Demo
    • 2.2. Import
    • 2.3. DisposeBag
  • 3. Observable Properties
    • Ý nghĩa
  • 4. Actions
  • 5. Subscribe
  • Tạm kết

Chào bạn đến với Fx Studio. Nếu bạn là người theo dõi series RxSwift này của Fx Studio ngay từ đầu. Thì đó là cả một chặng đường dài. Và bài viết này sẽ mở đầu cho một miền đất mới, đó là RxSwift UIKit. Để nói đầy đủ một chút là sử dụng RxSwift trong framework UIKit.

Dành cho các bạn chưa đọc qua phần đầu tiên của series, thì mình đã tổng hợp hết vào một bài viết. Bạn tham khảo bài viết qua link sau:

    • RxSwift – Phần 1 : Cơ bản

Còn mọi thứ đã ổn rồi, thì …

Bắt đầu thôi!

Chuẩn bị

    • Xcode 11
    • Swift 5.x

Bắt đầu từ bài viết này, chúng ta tạm thời chia tay em Playground và đến với iOS Project quen thuộc nha. Về project, mình khuyên bạn nên tự do sáng tạo. Các bài viết của mình mang tính chất tham khảo. Khi sáng tạo, bạn có nhiều bài toán của riêng bạn để giải quyết. Khi đó bạn sẽ học hỏi được nhiều hơn.

Và tất nhiên, Fx Studio vẫn sẽ có cho bạn một project tham khảo. Bạn có thể checkout project tham khảo này:

  • Link: checkout
  • Thư mục: /Examples/BasicRxSwift

1. RxSwift vs. UIKit

Về việc sử dụng RxSwift trong UIKit, mình chỉ giới hạn trong phạm vi sử dụng RxSwift là 1 framework. Về mặt này, RxSwift rất hữu ích cho bạn và nó giải quyết được rất nhiều vấn đề thường gặp trong lúc làm dự án iOS.

Mô hình hay kiến trúc cho project thì sẽ không được đưa vào trong các bài viết của phần RxSwift vs. UIKit này. Mà bạn hãy đọc bài viết với tâm tư tình cảm của một bạn iOS Developer mới vừa học xong iOS. Do đó, cũng có thể gọi phần 2 này là …

RxSwift cho mọi người

Các bài toán & vấn đề đặt ra trong phần này sẽ là:

  • Vấn đề cơ bản mà 1 bạn dev iOS làm việc hằng ngày hay gặp
  • Giải quyết các logic cơ bản
  • Bước đầu áp dụng việc viết Model
  • Không cần phải thay đổi nhiều thứ trong project hiện tại của bạn
  • …

Với kiến thức cơ bản mà bạn tìm hiểu ở phần 1 RxSwift, thì đã đủ để cho bạn giải quyết tất cả các vấn đề ở trên đưa ra rồi. Và bạn chưa cần sử dụng tới RxCocoa hay bất cứ hàng nóng nào thêm đâu.

Qua giới thiệu, mình hi vọng bạn sẽ không cần phải lo lắng nhiều khi bắt đầu lại với RxSwift trong UIKit. EZ!

2. Setup

2.1. Project Demo

Vì project demo được sử dụng cho rất nhiều ví dụ nên nó khá là đồ sộ. Tuy nhiên, bạn chỉ cần để tâm vào các file mà mình đề cập tới mà thôi. Về project thì mình sử dụng như sau:

  • Không sử dụng Storyboard (nếu bạn quên cách tạo thì xem ở đây).
  • CocoaPod để cài đặt thư viện RxSwift (cách cài đặt thì xem ở đây).

Bạn hãy bắt đầu với file RegisterViewController.swift . Nó cũng có giao diện khá đơn giản.

Giao diện đầu tiên bao gồm:

  • UIImageView để sử dụng làm avatar
  • 3 UITextField lần lượt cho username, password & email
  • 2 UIButton để register & clear dữ liệu trong các textfield

Bạn hãy sáng tạo thêm nha!

2.2. Import

Mọi thứ sẽ bắt đầu bằng việc import thư viện RxSwift vào trong file swift của bạn. Bạn hãy mở file RegisterViewController và thêm 2 dòng import sau đây vào.

import RxSwift
import RxCocoa

Bạn cũng không cần để ý tới RxCocoa nha, vì đôi khi ta dùng một số class của nó. Còn về phạm vi bài viết thì mình sẽ cố gắng sử dụng tất cả RxSwift để giải quyết bài trên UIKit.

Và toàn bộ code của file RegisterViewController ban đầu như sau:

import UIKit
import RxSwift

class RegisterViewController: UIViewController {
    
    // MARK: Outlets
    @IBOutlet weak var avatarImageView: UIImageView!
    @IBOutlet weak var usernameTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var registerButton: UIButton!
    
    // MARK: Properties
    var avatartIndex = 0
    
    // MARK: Life cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Register"
        
        configUI()
    }
    
    // MARK: Config
    func configUI() {
        avatarImageView.layer.cornerRadius = 50.0
        avatarImageView.layer.borderWidth = 5.0
        avatarImageView.layer.borderColor = UIColor.gray.cgColor
        avatarImageView.layer.masksToBounds = true
        
        let leftBarButton = UIBarButtonItem(title: "Change Avatar", style: .plain, target: self, action: #selector(self.changeAvatar))
        self.navigationItem.leftBarButtonItem = leftBarButton
    }
    
    // MARK: Actions
    @IBAction func register(_ sender: Any) {
    }
    
    @IBAction func clear(_ sender: Any) {
    }
    
    @objc func changeAvatar() {
        avatarImageView.image = UIImage(named: "avatar_1")
    }
    
}

2.3. DisposeBag

Thứ quan trọng tiếp theo chính là Túi rác quốc dân. Đây là thứ mà bạn bắt buộc phải có trong class ViewController của bạn.

Vì nó giúp bạn quản lý các subscriptions và bộ nhớ tốt nhất & tự động.

Bạn tạo một property mới cho RegisterViewController như sau:

    private let bag = DisposeBag()

Tuỳ thuộc vào ViewController của bạn đóng vài trò như thế nào trong một flow màn hình. Thì bạn sẽ có cách giải phóng các subscription theo từng cách khác nhau. Còn với ví dụ này, khi nào ViewController giải phóng thì bag sẽ giải phóng theo. Đi theo bag là các subscription của nó cũng bay hơi theo. EZ!

3. Observable Properties

Mình gọi chung là Observable cho các properties của ViewController. Nó có thể là:

  • Observable
  • Subject
  • Traits

Về ví dụ demo, chúng ta sẽ tạo 1 property quản lý avatart như sau:

private let image = BehaviorRelay<UIImage?>(value: nil)

Tại sao là Relay , vì:

  • Nó không bao giờ kết thúc
  • Dữ liệu của nó sẽ liên quan tới dữ liệu của một UI Control trong View

Người tiền nhiệm của nó trong RxSwift trước đây là Variable.

Còn việc chọn BehaviorRelay là vì mong muốn lúc nào cũng phải có giá trị khi có subscriber đăng ký tới. Còn kiểu dữ liệu là UIImage? để phù hợp với avatartImageView.image.

Cách sử dụng nó thì như sau:

  • Phát đi 1 dữ liệu
image.accpet(UIImage(...))
  • Lấy giá trị hiện tại của nó
image.value

Ý nghĩa

Mình đã trình bày 1 lèo các bước để bạn thêm một thuộc tính cho ViewController với kiểu là một Observable. Tại sao phải thêm thuộc tính kiểu này?

Giải quyết bài toán Rx hay Reactive Programming thì bạn cần phải có nguồn phát (Observable). Đó sẽ là tâm điểm để phát sinh các sự kiện và kéo theo sự thay đổi về mặt giao diện của ViewController.

Bên cạnh đó, sử dụng các Relay được xem là cách kết nối giữa code Rx & code non-Rx. Tức là, bạn không cần phải thay đổi quá nhiều code trong project hiện tại của bạn.

Số lượng các thuộc tính này được sử dụng thì tuỳ thuộc vào các use-case trong ViewController. Chứ không phải cứ 1 UI Control thì phải có 1 Observable đi kèm. Như vậy quá máy móc và đôi khi gây ra các hiệu ứng phụ mà mình không kiểm soát được hết các dòng dữ liệu.

4. Actions

Phần này, mình sẽ làm nhiều bạn thất vọng. Vì mình sẽ không dùng tới button.rx.tap. Đó là cái tạo nên thương hiệu của RxSwift. Nhưng nhiều bạn lại hiểu sai, chỗ không gian .rx ở đây chính là của RxCocoa. Qua phần 3 của series thì mình sẽ dùng tới không gian .rx đó. Còn bây giờ, mọi thứ vẫn như lúc bạn mới học iOS.

Bắt các sự kiện người dùng sẽ thông qua các IBActions.

Quay về demo của mình nào. Sang phần Actions chính là xử lý các sự kiện mà người dùng tác động lên giao diện. Trong ví dụ, thì bạn mở function changeAvatar và thêm phần xử lý này vào

@objc func changeAvatar() {
        let img = UIImage(named: "avatar_1")
        image.accept(img)
    }

(các name cho UIImage, thì bạn có thể sử dụng các image của riêng bạn nha.)

Giờ thử run project và xem kết quả nào.

Vẫn không có gì thay đổi hết. Tất nhiên là bạn chưa thực hiện bước sau cùng. Đó là lắng nghe tới những gì được phát ra.

5. Subscribe

Sau việc emit dữ liệu, là việc subscribe để nhận được dữ liệu. Việc subscribe với chúng ta đã làm nhiều rồi. Nhưng quan trọng, trong đó là phải cập nhật UI lại với dữ liệu mới. Quay về code demo, bạn truy cập tới viewDidLoad của RegisterViewController và thêm code subscribe vào.

override func viewDidLoad() {
        super.viewDidLoad()
        title = "Register"
        
        configUI()
        
        //subscription
        image
            .subscribe(onNext: { img in
                self.avatarImageView.image = img
            })
            .disposed(by: bag)
    }

Toàn là kiến thức cũ thôi. Vì BehaviorRelay cũng là một Subject, nên hoàn toàn có thể subscribe nó. Bạn chỉ cần quan tâm tới .onNext mà thôi. Các trường hợp error hay completion là không bao giờ xảy ra với Relay.

Khi bạn quen với Reactive Programming rồi, việc thiết lập các subscriber này bạn sẽ làm lúc ban đầu luôn. Mọi thứ sẽ được khai báo (từ outlet tới action đều được Rx hoá ….) và chỉ cần tương tác 1 phát là kéo theo các sự thay đổi khác diễn ra. Quá trình này hoạt động tự động và độc lập với nhau.

Và khi bạn muốn BehaviorRelay có thêm error hay completed thì có thể biến đổi một chút như sau:

image.asObservable()
            .subscribe(onNext: { img in
                self.avatarImageView.image = img
            })
            .disposed(by: bag)

Toán tử asObservable() sẽ xoá đi mọi khoảng cách để chúng ta thêm tự tin gần nhau hơn. Bạn hay run project và xem kết quả được như mình mong muốn hay không.

Ngoài ra, bạn có thể xử lý để áp dụng cho nhiều thay đổi lên nhiều UI Control trong ViewController với mỗi lần nhận được dữ liệu. Ví dụ như sau:

func updateUI() {
	// thay đổi Lable
	
	// thay đổi Button
	
	// update Tableview
	
	// ...
}

Update lại chỗ subcriber thì như sau:

images.asObservable()
		.subscribe(onNext: { [weak self] photos in
				self?.updateUI() 
				})
		.disposed(by: bag)

 

OKAY! Tới đây thì mình xin kết thúc bài viết đầu tiên và Hello thành công ViewController. Nếu có gì thắc mắc hay góp ý cho mình thì bạn có thể để lại bình luận hoặc gởi email theo trang Contact.

Tạm kết

  • Setup & Import RxSwift vào ViewController
  • Thêm các thuộc tính cần thiết (Observable & DisposeBag)
  • Phát dữ liệu đi thông qua các IBAction
  • Update UI bằng subscribe tới các Observable

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

FacebookTweetPinYummlyLinkedInPrintEmailShares20

Related Posts:

  • RxSwift - Hello world!
    RxSwift - Hello world!
  • RxSwift - Hello Subjects
    RxSwift - Hello Subjects
  • Tích hợp UIView (UIKit) vào SwiftUI Project - SwiftUI Notes #15
    Tích hợp UIView (UIKit) vào SwiftUI Project - SwiftUI Notes…
  • RxSwift vs. UIKit – Networking
    RxSwift vs. UIKit – Networking
Tags: rxswift
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:

  • RxSwift vs. UIKit – Working with Cache Data
    RxSwift vs. UIKit – Working with Cache Data
  • Tích hợp SwiftUI vào UIKit Project - SwiftUI Notes #13
    Tích hợp SwiftUI vào UIKit Project - SwiftUI Notes #13
  • SwiftUI - Phần 3 : Tích hợp SwiftUI và UIKit
    SwiftUI - Phần 3 : Tích hợp SwiftUI và UIKit
  • RxSwift vs. UIKit – Tương tác giữa các ViewController
    RxSwift vs. UIKit – Tương tác giữa các ViewController
  • RxSwift - Hello Subjects
    RxSwift - Hello Subjects

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!