This article explains how to appropriately implement the delegate, observer, and singleton design patterns in Swift. These design patterns help to create a structured and clean codebase, enhancing code reusability and maintainability.
The delegate pattern allows one object to communicate with another without requiring tight coupling. It is commonly used in iOS for components like UITableView. Here’s a simple example:
class DataLoader {
var delegate: DataLoaderDelegate?
func loadData() {
// Simulate data loading
let data = "Data Loaded"
delegate?.didLoadData(data: data)
}
}
protocol DataLoaderDelegate {
func didLoadData(data: String)
}
class ViewController: DataLoaderDelegate {
let dataLoader = DataLoader()
func setup() {
dataLoader.delegate = self
dataLoader.loadData()
}
func didLoadData(data: String) {
print(data)
}
}
The observer pattern is used when an object needs to notify other objects about changes in its state. This is useful in situations like notifications or event handling. Here’s a basic example:
class Notifier {
private var observers = [Observer]()
func addObserver(_ observer: Observer) {
observers.append(observer)
}
func notifyObservers() {
for observer in observers {
observer.update()
}
}
}
protocol Observer {
func update()
}
class Listener: Observer {
func update() {
print("Observer notified!")
}
}
The singleton pattern restricts a class to a single instance and provides a global point of access to it. This is often used for managing shared resources like configuration settings or a shared database connection.
class Singleton {
static let shared = Singleton()
private init() {
// Private initialization to prevent others from using the default '()' initializer
}
func doSomething() {
print("Doing something...")
}
}
// Usage
Singleton.shared.doSomething()
How do I avoid rehashing overhead with std::set in multithreaded code?
How do I find elements with custom comparators with std::set for embedded targets?
How do I erase elements while iterating with std::set for embedded targets?
How do I provide stable iteration order with std::unordered_map for large datasets?
How do I reserve capacity ahead of time with std::unordered_map for large datasets?
How do I erase elements while iterating with std::unordered_map in multithreaded code?
How do I provide stable iteration order with std::map for embedded targets?
How do I provide stable iteration order with std::map in multithreaded code?
How do I avoid rehashing overhead with std::map in performance-sensitive code?
How do I merge two containers efficiently with std::map for embedded targets?