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 November 12, 2019

Singleton Pattern trong 10 phút

iOS & Swift

Contents

  • Chuẩn bị
  • 1. Singleton
  • 2. Các kiểu Singleton
    • 2.1. Biến toàn cục
    • 2.2. Biến Static
    • 2.3. Kiểu function
  • 3. Cách viết Singleton
    • 3.1. Struct muôn nơi
    • 3.2. Biến toàn cục
    • 3.3. One-line
    • 3.4. Cách đề nghị
  • Tạm kết

Chào bạn tới với Fx Studio, bài viết này sẽ nói về một chủ đề rất quen thuộc trong giới lập trình Swift hay giới lập trình nói chung. Đó là Singleton Pattern. Một mẫu design pattern khá là phổ biến trong hầu hết các ngôn ngữ lập trình.

Bây giờ chúng ta sẽ tìm hiểu nó trong Swift sẽ như thế nào? Và cách viết singleton thế nào là ổn nhất? Nếu bạn chưa tìm hiểu về Swift thì có thể bổ sung kiến thức trước khi vào bài:

    • Basic Swift trong 10 phút

Chuẩn bị

  • MacOS 10.14.4
  • Xcode 11.0
  • Swift 5.1

1. Singleton

Ít nhiều bạn dev iOS thì cũng một lần trong đời thấy qua các đoạn code sau:

// Shared URL Session
let sharedURLSession = URLSession.shared

// Default File Manager
let defaultFileManager = FileManager.default

// Standard User Defaults
let standardUserDefaults = UserDefaults.standard

// Default Payment Queue
let defaultPaymentQueue = SKPaymentQueue.default()

Đó chính là những mẫu singleton mà Apple sử dụng trong core hệ thống của họ. Vậy singleton là gì?

Singleton Pattern là pattern đảm bảo rằng một lớp chỉ có một thể hiện (instance) duy nhất và trong đó cung cấp một cổng giao tiếp chung nhất để truy cập vào lớp đó.

Singleton pattern là một pattern vô cùng hữu dụng. Đôi khi bạn muốn chắc chắc chắn rằng chỉ có một instance của một đối tượng được khởi tạo và ứng dụng của bạn chỉ sự dụng instance đó . Đó là mục tiêu chính và duy nhất của singleton pattern.

Nhưng mọi vấn đề đều có mặt tốt và mặt xấu, singleton cũng không tránh được nó.

  • Tốt
    • Nhanh, tiện lợi
    • Truy cập mọi lúc, mọi nơi
    • Lưu trữ dữ liệu đơn giản
    • Truyền dữ liệu đơn giản
  • Xấu
    • Khó kiểm soát
    • Khó quản lý
    • Nguy hiểm khi dùng chung nhiều Thread
    • Sự quá lệ thuộc vào nó trong điều phối dữ liệu

Xấu hay Tốt thì do bản thân mình quyết định. Nhưng để sử dụng nó một cách tối ưu nhất thì bạn tham sao các kiểu singleton dưới đây.

2. Các kiểu Singleton

2.1. Biến toàn cục

Phương pháp đơn giản để ứng dụng Singleton Pattern là tạo ra một biến toàn cục (Global Variables).

Tạo ra giữa trời đất này và ảnh hưởng tới toàn bộ thế gian.

Tham khảo code ví dụ sau:

//1
class MyClass {
    init() {}
}

//2
let shareMyClass = MyClass()

Trong đó:

  1. Khai báo 1 class hoặc bạn có thể sử dụng bất kì class nào bạn muốn
  2. Khai báo 1 biến hoặc 1 hằng và sử dụng nó

Tuỳ thuộc vào phạm vị bạn sử dụng như thế nào thì tầm ảnh hưởng của nó sẽ theo như vậy.

2.2. Biến Static

Tham khảo đoạn code sau:

class User {
    init() {}
}

static var defaultUser = User()

Chúng ta có thể thấy, thì một biến/hằng bất kì với khai báo static thì nó sẽ không bị mất đi. Hiển nhiên, bạn có thể truy cập tới nó ở bất kì đâu. Và nó trở thành Singleton.

Có 1 điểm hạn chế cho việc khai báo biến đó giữa trời giữa đất như vậy. Đó là hạn chế về mặt quản lý.

class User {
    //singleton
    static var defaultUser = User(name: "default user")
    
    //properties
    var name: String
    
    //init
    init(name: String) {
        self.name = name
    }
    
    //method
    func say() {
        print(name)
    }
}


User.defaultUser.say()

Chúng ta di chuyển đối tượng stactic defaultUser vào trong class User. Khi đó việc truy cập tới defaultUser có vẻ dễ hiểu hơn nhiều.

Đây cũng là cách khuyến khích bạn nên làm.

2.3. Kiểu function

Đôi khi bạn lại thấy nhiều đối tượng singleton là shared hay shared(). Thì đó cũng là kiểu singleton với cách truy cập là gọi function của Class để trả về 1 đối tượng duy nhất.

class User {
    //singleton
    private static var defaultUser = User(name: "default user")
    
    static func shared() -> User {
        return defaultUser
    }
    
    //properties
    var name: String
    
    //init
    init(name: String) {
        self.name = name
    }
    
    //method
    func say() {
        print(name)
    }
}

User.shared().say()

Với kiểu này thì bạn có thể che dấu đi biến static trên kia. Nhìn trông pro hơn nhiều.

Nôm na thì chúng ta có 3 kiểu như trên, còn lại là viết singleton như thế nào là ổn nhất? Và cách nào, kiểu nào là tốt nhất? Thì tham khảo tiếp phần sau.

3. Cách viết Singleton

Chúng ta giả định có 1 class tên là DataManager có nhiệm vụ quản lý Database trong ứng dụng. Cách tốt nhất để quản lý và xử lý thì cần xử lý tập trung với 1 đối tượng duy nhất. Với yêu cầu trên thì chúng ta sẽ viết singleton cho class này.

class DataManager {
    
    //properties
    var databaseName: String = ""
    
    // init
    init() {}
    
    // config database
    func configDatabase(databaseName: String) {
        self.databaseName = databaseName
    }
    
    //open database
    func open() {
        print("open: \(databaseName)")
    }
    
    //save database
    func save() {
        print("save: \(databaseName)")
    }
}

3.1. Struct muôn nơi

//singleton
    class var shared: DataManager {
        struct Static {
            static var instance = DataManager()
        }
        
        return Static.instance
    }

Thêm đoạn code trên vào trong class User, để tạo ra 1 singleton cho nó. Sử dụng như sau:

DataManager.shared.open()

Về bản chất thì chúng cũng chỉ là 1 biến static của Class. Nhưng giờ đây nó được lồng vào 1 struct. Bản chất của nó gọi là type property của class.

Với cách này thì kiểu gừng càng già càng cay.

3.2. Biến toàn cục

Đã được giải thích ở trên. Bạn chỉ cần đưa nó ra ngoài class là xong.

//1
private let sharedDataManager = DataManager()


//2
class var shared: DataManager {
        return sharedDataManager
    }

Trong đó:

  1. Tạo 1 biến static ở đâu đó cũng được, tốt nhất ngoài phạm vi class
  2. Edit lại function shared ở trên, với return về đối tượng static kia

Với cách này thì kiểu nước sông không phạm nước giếng.

3.3. One-line

Chúng ta lại tham khảo cách viết tiếp theo

class DataManager {
    
    //singleton
    static let shared = DataManager()
    
...
}

Singleton được tạo ra với 1 dòng duy nhất. Về sử dụng thì truy suất trực tiếp

DataManager.shared.open()

Với cách này thì kiểu ngon, bổ , rẻ.

3.4. Cách đề nghị

Từ trên xuống tới đây, thì thật giả lẫn lộn. Giờ chúng ta tham khảo cách mà theo mình là bạn nên sử dụng. Tham khảo đoạn code sau:

class DataManager {
    
    //singleton
    private static var sharedDataManager: DataManager = {
        let dataManager = DataManager()
        
        //config
        dataManager.configDatabase(databaseName: "BD")
        
        return dataManager
    }()
    
    class func shared() -> DataManager {
        return sharedDataManager
    }
    
    //properties
    var databaseName: String = ""
    
    // init
    private init() {}
    
    // config database
    func configDatabase(databaseName: String) {
        self.databaseName = databaseName
    }
    
    //open database
    func open() {
        print("open: \(databaseName)")
    }
    
    //save database
    func save() {
        print("save: \(databaseName)")
    }
}


DataManager.shared().open()

Trong đó:

  • sharedDataManager là một type property và được khai báo private
  • sharedDataManager được gián giá trị bằng 1 closure với return là kiểu DataManager
  • Với việc sử dụng closure thì đảm bảo cho việc mình có thể chạy thêm các function cần thiết cho đối tượng singleton. Thường sẽ là các hàm config dữ liệu
  • shared() là một type method, sử dụng bằng cách dùng tên class để gọi. Method return về đối tượng sharedDataManager
  • Để đảm bảo cho đối tượng singleton là duy nhất, thì private init. Không cho phép việc tạo thêm đối tượng khác nữa.

Các cách viết trên chỉ mang tính chất tham khảo. Tuỳ thuộc vào yêu cầu của dự án mà bạn sẽ quyết định dùng cách nào.

Chúc bạn thành công với singleton.

Tạm kết

  • Biết về Singletion Pattern
  • Các kiểu Singleton
  • Các cách viết Singleton

 

FacebookTweetPinYummlyLinkedInPrintEmailShares30

Related Posts:

  • 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
  • Cơ bản về Actor trong 10 phút - Swift 5.5
    Cơ bản về Actor trong 10 phút - Swift 5.5
  • Convenience Initializer trong 10 phút
    Convenience Initializer trong 10 phút
Tags: basic ios tutorial, iOS, singleton
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:

  • Cơ bản về async/await trong 10 phút - Swift 5.5
    Cơ bản về async/await trong 10 phút - Swift 5.5
  • Task & Task Group trong 10 phút - Swift 5.5
    Task & Task Group trong 10 phút - Swift 5.5
  • Keychain trong 10 phút - iOS
    Keychain trong 10 phút - iOS
  • Generics trong 10 phút - Swift
    Generics trong 10 phút - Swift
  • File Manager trong 10 phút - Swift
    File Manager trong 10 phút - Swift

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!