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 June 30, 2020

Convenience Initializer trong 10 phút

iOS & Swift

Contents

  • Chuẩn bị
  • 1. Convenience Initializer là gì?
  • 2. Các trường hợp sử dụng Convenience Initializer
    • 2.1. Phụ trợ
    • 2.2. Kế thừa
    • 2.3. Ghi đè
  • Tạm kết

Chào bạn đến với Fx Studio. Bài viết này sẽ trình bày một phần rất hẹp trong ngôn ngữ Swift. Đó là Convenience Initializer. Để chuẩn bị vào bài, bạn cần phải nắm được một số kiến thức cơ bản như sau:

    • Basic Swift trong 10 phút

Chuẩn bị

  • Swift 5.x
  • Playground

Để demo code cho bài này, chỉ cần sử dụng Playground là ổn rồi. Bạn tự sáng tạo thêm các ví dụ cho riêng bạn, hoặc dùng chính nhưng class mà bạn đang gặp vấn đề để giải quyết nó luôn.

1. Convenience Initializer là gì?

Bạn là một iOS Developer thì có bao giờ bạn tự hỏi là:

Có bao nhiều loại cho hàm khởi tạo của class trong ngôn ngữ lập trình Swift?

Mình đảm bảo là sẽ trên 80% dev được hỏi, thì sẽ không biết câu trả lời. Vì một điều hiển nhiên là Swift đã cung cấp cho bạn các Default Initializers sẵn rồi.

Ví dụ sau:

class ShoppingListItem {
    var name: String?
    var quantity = 1
    var purchased = false
}

var item = ShoppingListItem()

Như bạn đã thấy, khi các thuộc tính của class đã được cung cấp giá trị lúc khai báo. Thì cái hàm init mặc định đó sẽ không cần dùng tới. Và nó sẽ được gọi khi thực thi lệnh ShoppingListitem().

Vậy

Mấy cái hàm init viết thêm thì gọi là gì?

Vâng, chúng nó sẽ được gọi là Designated initializers. Cái thứ mà hiển nhiên tồn tại lâu ni cũng có cái tên nghe sang chảnh phải không. Dành cho bạn nào quên cú pháp thì xem hình dưới (hình chuẩn từ Apple).

Và, nhiều lúc viết thêm thuộc tính hay viết thêm hàm init thì Xcode báo lỗi. Và theo một quy luật hiển nhiên nữa, dev iOS lại cứ nhấn fix auto một cách vô thức. Lúc đó:

Từ khoá convenience sẽ xuất hiện và bạn có thắc mắc nó là gì không?

(nếu bạn để ý tới nói, chứ thật ra là cũng trên 80% dev iOS cũng không để ý tới)

Convenience Initializer là một hàm khởi tạo phụ trợ cho các hàm khởi tạo khác trong class. Sử dụng để bổ sung các giá trị cho các thuộc tính hoặc tuỳ biến lại một số thuộc tính với các giá trị đầu vào khác nhau cho từng trường hợp.

Cú pháp như sau:

Ví dụ với code cho nó thông não một tý nha:

class BaseClass {
  var a: Int
  var b: Int
  
  init(a: Int, b: Int) {
    self.a = a
    self.b = b
  }
  
  convenience init(numbers: [Int]) {
    self.init(a: numbers[0], b: numbers[1])
  }
  
  func show() {
    print("a = \(a), b = \(b)")
  }
}

Theo trên thì có 1 class là BaseClass  với 2 thuộc tính là a và b. Và có 1 hàm khởi tạo với 2 tham số cho a & b.

Viết thêm một hàm khởi tạo phụ trợ với tham số là Array Int. Nhưng chúng ta không thay đổi gì hết, chỉ cần lấy ra 2 số và gọi hàm init kia mà thôi. Đơn giản phải không nào, còn cách dùng như sau:

let obj1 = BaseClass(a: 1, b: 2)
obj1.show()

let obj2 = BaseClass(numbers: [5,10])
obj2.show()

2. Các trường hợp sử dụng Convenience Initializer

Tóm tắt một chút:

  • Designated initializers là các hàm khởi tạo truyền thống như trước đây.
  • Convenience Initializer là các hàm khởi tạo phụ trợ thêm cho các hàm truyền thống.

Và một điều chú ý:

Cũng có nhưng quy định riêng cho Convenience Initializer trong khi sử dụng.

Ta xem qua hình sau là mô tả thiết kế cho 2 loại hàm khởi tạo trong class của ngôn ngữ Swift.

Đợi một ngày đẹp trời nào đó, mình sẽ viết một bài nghiêm chỉnh giải thích tường tận sơ đồ trên của Swift. Và giải thích các luật áp dụng cho 2 loại hàm khởi tạo với kiểu Type Class trong Swift.

Việc quan trọng là dựa vào sơ đồ trên mà mình tóm tắt ra 3 cách dùng cơ bản nhất cho convenience.

2.1. Phụ trợ

Đây là cách sử dụng chính của Convenience Initializer. Cho dù là Supper Class hay SubClass đi nữa, hoặc bất kỳ class nào … Thì bạn cần phải thành thạo việc sử dụng này.

Tập trung vào việc phụ trợ thêm cho các hàm khởi tạo khác có sẵn trong class. Đó là về mặt cung cấp giá trị cho các thuộc tính được khai báo hoặc tính toán dữ liệu lúc khởi tạo.

Ví dụ, bạn có 1 class là Human như sau:

class Human {
  // Properties
  var name: String
  
  // init
  init(name: String) {
    self.name = name
  }

  // methods
  func show() {
    print("Name: \(name)")
  }
}

Và khi sử dụng cho việc tạo đối tượng thì như thế này:

let boo = Human(name: "Boo")
boo.show()

Nhưng bạn muốn khởi tạo 1 đối tượng với lệnh đơn giản là Human(). Thì điều này là không thể được, vì 2 nguyên nhân cơ bản:

  • Bạn chưa viết lại hàm init()
  • Bạn cần phải cung cấp giá trị cho biến name

Giải quyết việc này thì nhờ tới convenience init và đám code còn lại không đụng tới.

convenience init() {
    self.init(name: "[NoName]")
  }

Và việc gọi hàm Human() với không có tham số name, đối tượng Human vẫn được tạo ra, nhưng name sẽ là [NoName].

2.2. Kế thừa

Mục đích sử dụng tiếp theo sử dụng trong Kế thừa với lớp con. Bài toán rất cụ thể, lớp cha (Supper Class) đã chịu khó khởi tạo với rất nhiều thuộc tính của nó. Và lớp con (Subclass) có thêm vài thuộc tính của riêng nó nữa, nhưng bạn không cần thiết phải khởi tạo hết tất cả thuộc tính ở 2 class đó.

Ta có bài toán được minh hoạ như sau:

  • BaseClass
class BaseClass {
  var a: Int
  var b: Int
  
  init(a: Int, b: Int) {
    self.a = a
    self.b = b
  }
}
  • SubClass
class SubClass : BaseClass {
  var c: Int
  var d: Int
}

Và đây là hàm khởi tạo mà SubClass phải có. Nó khởi tạo bao gồm 2 phần:

  • Phần 1: sẽ gán các giá trị cho các thuộc tính của riêng nó
  • Phần 2: gọi tới super để gán các giá trị còn lại
init(a: Int, b: Int, c: Int, d: Int) {
    self.c = c
    self.d = d
    super.init(a: a, b: b)
  }

Giờ đây, bạn muốn custom 1 hàm init với chỉ 2 giá trị c & d. Còn a & b sẽ bằng 0. Với convenience:

convenience init(c: Int, d: Int) {
    self.c = c
    self.d = d
    super.init(a: 0, b: 0)
  }

Và Xcode sẽ báo lỗi. Vì do, convenience sẽ không truy cập được tới các hàm của lớp cha.

Cho nên bạn cần phải gọi như sau:

convenience init(c: Int, d: Int) {
    self.init(a: 0, b: 0, c: c, d: d)
  }

2.3. Ghi đè

Hoặc bạn sẽ có thêm một cách toàn mỹ hơn như sau:

class SubClass : BaseClass {
  var c: Int
  var d: Int
  
  override init(a: Int, b: Int) {
    c = 0
    d = 0
    super.init(a: a, b: b)
  }
  
  convenience init(a: Int, b: Int, c: Int, d: Int) {
    self.init(a: a, b: b)
    self.c = c
    self.d = d
  }
  
}

Thay vì viết một hàm init mới với 4 tham số. Thì bạn chỉ cần override lại hàm khởi tạo của lớp cha. Truyền các giá trị mặc định cho các thuộc tính của lớp con.

Cuối cùng, viết lại một hàm convenience đầy đủ 4 tham số, nhưng thao tác ngược lại với cách (2).

  • Phần 1: khởi tạo trước
  • Phần 2: gán giá trị sau

Với cách này, để cho bạn thêm cách xử lý khi nào cho thuộc tính của lớp nào với các giá trị mặc định. Hoặc khi nào cần phụ trợ riêng cho thuộc tính của lớp nào.

Qua 3 cách sử dụng cơ bản trên, hi vọng giúp ích bạn trong một số trường hợp khó khăn. Hoặc chủ động hơn, bớt lệ thuộc vào trình biên dịch hay gỡ lỗi của Xcode.

Tạm kết

  • Biết thêm về 2 loại hình khởi tạo class
  • Cách sử dụng Convenience Initializer
  • Cách hoạt động của các hàm Initializer trong Subclass

Bài viết được tham khảo tại đây! Cảm ơn bạn đã đọc bài viết này!

And Happy coding!

FacebookTweetPinYummlyLinkedInPrintEmailShares39

Related Posts:

  • Race Condition và giải pháp trong 10 phút - Swift
    Race Condition và giải pháp trong 10 phút - Swift
  • Generics trong 10 phút - Swift
    Generics trong 10 phút - Swift
  • Keychain trong 10 phút - iOS
    Keychain trong 10 phút - iOS
  • Sendable Protocol & @Sendable trong 10 phút - Swift 5.5
    Sendable Protocol & @Sendable trong 10 phút - Swift 5.5
Tags: basic ios tutorial, Swift
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:

  • Property Wrapper trong 10 phút
    Property Wrapper trong 10 phút
  • Quick trong 10 phút
    Quick trong 10 phút
  • Generics trong 10 phút - Swift
    Generics trong 10 phút - Swift
  • Race Condition và giải pháp trong 10 phút - Swift
    Race Condition và giải pháp trong 10 phút - Swift
  • Text View trong 10 phút - SwiftUI Notes #25
    Text View trong 10 phút - SwiftUI Notes #25

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!