Cách viết một Singleton sao cho đúng trong lập trình IOS với Swift
Trong lập trinh IOS chẳng mấy xa lạ với design pattent Singleton. Nhưng đã bao giờ bạn thực sự để ý cách viết và sử dụng nó sao cho thực sự hợp lý. Trong bài này chúng ta cùng nhau tìm hiểu cách viết và sử dụng singleton trong lập trình IOS cụ thể là ngôn ngữ swift sao cho đúng và hợp lý. Về cơ bản ...
Trong lập trinh IOS chẳng mấy xa lạ với design pattent Singleton. Nhưng đã bao giờ bạn thực sự để ý cách viết và sử dụng nó sao cho thực sự hợp lý. Trong bài này chúng ta cùng nhau tìm hiểu cách viết và sử dụng singleton trong lập trình IOS cụ thể là ngôn ngữ swift sao cho đúng và hợp lý. Về cơ bản có 3 điều cần nhớ về singleton:
- Singleton phải là duy nhất. Tức là chỉ có duy nhất một thể hiện trong suốt vòng đời của ứng dụng. Nó được xậy dựng như một biến global.
- Để singleton là duy nhất thi khi khởi tạo cần được private.
- Từ lưu ý số 1, chỉ cho phép có một instance được tạo ra trong suốt quá trình chạy ứng dụng, điều này có nghĩa nó cần một thread an toàn. Nếu một singleton được tạo ra không chính xác trong code, bạn có thể sẽ có 2 thread cùng khở tạo một singleton tại cùng một thời điểm. Điều này khiến nó không còn là duy nhất trừ khi chúng ta đưa nó vào một thread an toàn. Cách giải quyết ở đây là đưa hàm khởi tạo vào một dispatch_once GCD block. Nó giúp đảm bảo rằng singleton chỉ được chạy một lần duy nhất. Bây giờ chúng ta cùng đi qua các cách để tạo ra một singleton thông qua các giai đoạn bằng ngồn ngữ swift Swift 1.0 Đây là thời điểm khi swift mới ra đời. Chưa có nhiều hỗ trợ và ảnh hưởng nhiều bởi objective-C. Một ví dụ đơn giản
class TheOneSingleton { class var sharedInstance: TheOneSingleton { struct Static { static var oneToken: dispatch_once_t = 0 static var instance: TheOneSingleton? = nil } dispatch_once(&Static.oneToken) { Static.instance = TheOneSingleton() } return Static.instance! } }
Đây là một cách viết điển hình hồi đó và có thể dễ dàng tim ra trên các nguồn khác nhau. Nhưng đây là cách viết khá tệ vì nó đi ngược lại các phương châm cơ bản của ngôn ngữ swift: terse and expressive Sử dụng struct Để khắc phục các nhược điểm trên, thời điểm này họ sử dụng một phương pháp khác. Bằng cách lồng thêm struct vào. Cách này tuy cũ nhưng đến nay vẫn thi thoảng được dùng.
class TheOneSingleton { class var sharedInstance: TheOneSingleton { struct Static { static let instance = TheOneSingleton() } return Static.instance } }
Cách viết này cơ bản khắc phục được các nhược điểm của cách đầu tiên, tuy nhiên nó chỉ là tối ưu nhất tại thời điểm đó mà thôi. One Line Singleton Bắt đầu từ swift 1.2. Xuất hiện một cách để viết một singleton ngắn gọn hơn rất nhiều. Đó là sử dụng biết global.
class TheOneSingleton { class var sharedInstance: TheOneSingleton { return shared } } private let shared = TheOneSingleton()
Có một điều đặc biệt rằng tại sao ở đây chúng ta không còn thấy dispatch_once. Nhưng đầy là điều apple muốn. https://developer.apple.com/swift/blog/?id=7 Đoạn trích dẫn sau chứng minh rằng chúng được gói trong một dispatch_once
“The lazy initializer for a global variable (also for static members of structs and enums) is run the first time that global is accessed, and is launched as `dispatch_once` to make sure that the initialization is atomic. This enables a cool way to use `dispatch_once` in your code: just declare a global variable with an initializer and mark it private.” — Apple's Swift Blog
Tuy nhiên với cách viết này đưa khiến chúng ta gắp vấn đề khi đặt tên, trùng tên biến. Điều này khiến một cách tối ưu được đưa ra
class TheOneSingleton { static let sharedInstance = TheOneSingleton() }
Rõ ràng hơn nữa là kể từ swift 3 dispatch_once không còn được hỗ trợ nữa. Tuy nhiên để đảm bảo tính duy nhất của singleton bạn đừng quên private phương thức khởi tạo của class nhé
class TheOneSingleton { static let sharedInstance = TheOneSingleton() private init() {} }
Điều này ngăn cản người khác có thể sử dụng phương thức khởi tạo default để phá vỡ tinh duy nhất của singleton Kết Luận Trong phần này mình đã nói về một số cách để viết ra một singleton sử dụng swift, Tuy nhiên với bạn có thể chứng mình cả 3 phương pháp đều chỉ khởi tạo một lần bằng cách đưa cả 3 phương pháp này vào source code đặt debug để kiểm tra. Nếu có thắc mắc gì vui long comment bên dưới nhé.