Паттерны проектирования в Swift: практическое руководство для iOS/macOS разработчиков
Паттерны проектирования (design patterns) — это проверенные решения типовых задач в разработке программного обеспечения. Для iOS/macOS разработчиков знание паттернов на Swift — обязательный навык, позволяющий создавать масштабируемые, тестируемые и поддерживаемые приложения. В этой статье мы разберем 4 ключевых паттерна с реальными примерами кода.
1. Singleton (Одиночка)
Один из самых популярных паттернов в iOS-разработке. Гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к нему. Используется для управления общими ресурсами: UserDefaults, NetworkManager, Database.
Реализация Singleton в Swift
class NetworkManager {
static let shared = NetworkManager()
private init() { }
func fetchData(from url: URL) {
// логика запроса
print("Данные получены из \(url)")
}
}
// Использование
NetworkManager.shared.fetchData(from: URL(string: "https://api.example.com")!)
Важно: В Swift 5.5+ используйте actor для потокобезопасности:
actor SettingsManager {
static let shared = SettingsManager()
private var settings: [String: String] = [:]
func setValue(_ value: String, forKey key: String) {
settings[key] = value
}
func getValue(forKey key: String) -> String? {
return settings[key]
}
}
2. Factory Method (Фабричный метод)
Определяет интерфейс для создания объектов, но позволяет подклассам изменять тип создаваемых объектов. Идеально подходит для создания различных типов UI-компонентов или моделей данных.
Пример: создание кнопок для разных платформ
protocol Button {
func render()
}
class iOSButton: Button {
func render() {
print("Отображаем iOS кнопку с закругленными углами")
}
}
class macOSButton: Button {
func render() {
print("Отображаем macOS кнопку с градиентом")
}
}
protocol ButtonFactory {
func createButton() -> Button
}
class iOSButtonFactory: ButtonFactory {
func createButton() -> Button {
return iOSButton()
}
}
class macOSButtonFactory: ButtonFactory {
func createButton() -> Button {
return macOSButton()
}
}
// Использование
let factory: ButtonFactory = iOSButtonFactory()
let button = factory.createButton()
button.render() // "Отображаем iOS кнопку с закругленными углами"
3. Observer (Наблюдатель)
Позволяет объектам подписываться на события и получать уведомления об изменениях. В Swift реализуется через NotificationCenter, Combine или didSet.
Реализация через Combine (iOS 13+)
import Combine
class WeatherStation {
@Published var temperature: Double = 0.0
func updateTemperature(_ temp: Double) {
temperature = temp
}
}
class WeatherDisplay {
var subscriptions = Set<AnyCancellable>()
let station = WeatherStation()
func startObserving() {
station.$temperature
.sink { [weak self] newTemp in
print("Температура изменилась: \(newTemp)°C")
self?.updateUI(with: newTemp)
}
.store(in: &subscriptions)
}
private func updateUI(with temp: Double) {
// Обновление интерфейса
}
}
Классическая реализация через протокол
protocol Observer: AnyObject {
func update(value: Int)
}
class Subject {
private var observers = [Observer]()
func attach(_ observer: Observer) {
observers.append(observer)
}
func detach(_ observer: Observer) {
observers.removeAll { $0 === observer }
}
func notify(value: Int) {
observers.forEach { $0.update(value: value) }
}
}
class ConcreteObserver: Observer {
let name: String
init(name: String) {
self.name = name
}
func update(value: Int) {
print("\(name) получил новое значение: \(value)")
}
}
// Использование
let subject = Subject()
let observer1 = ConcreteObserver(name: "Наблюдатель 1")
let observer2 = ConcreteObserver(name: "Наблюдатель 2")
subject.attach(observer1)
subject.attach(observer2)
subject.notify(value: 42)
4. Delegate (Делегат)
Фундаментальный паттерн для iOS/macOS. Позволяет одному объекту делегировать выполнение задач другому объекту. Широко используется в UIKit: UITableViewDelegate, UITextFieldDelegate.
Создание собственного делегата
protocol PaymentDelegate: AnyObject {
func paymentDidComplete(amount: Double)
func paymentDidFail(error: Error)
}
class PaymentManager {
weak var delegate: PaymentDelegate?
func processPayment(amount: Double) {
// Логика обработки платежа
let success = Bool.random()
if success {
delegate?.paymentDidComplete(amount: amount)
} else {
let error = NSError(domain: "PaymentError", code: -1)
delegate?.paymentDidFail(error: error)
}
}
}
class ViewController: UIViewController, PaymentDelegate {
let paymentManager = PaymentManager()
override func viewDidLoad() {
super.viewDidLoad()
paymentManager.delegate = self
}
@IBAction func payButtonTapped() {
paymentManager.processPayment(amount: 99.99)
}
// MARK: - PaymentDelegate
func paymentDidComplete(amount: Double) {
showAlert(message: "Оплата \(amount) руб. прошла успешно!")
}
func paymentDidFail(error: Error) {
showAlert(message: "Ошибка: \(error.localizedDescription)")
}
private func showAlert(message: String) {
let alert = UIAlertController(title: "Результат", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
}
Заключение
Освоение паттернов проектирования в Swift — ключевой шаг к профессиональной разработке под iOS/macOS. Мы рассмотрели:
- Singleton — для управления единственным экземпляром (NetworkManager, UserDefaults)
- Factory — для гибкого создания объектов без привязки к конкретным классам
- Observer — для реактивного обновления интерфейса (Combine, NotificationCenter)
- Delegate — для развязывания компонентов и обработки событий
На практике комбинируйте эти паттерны с архитектурными подходами (MVVM, VIPER) для создания надежных приложений. Помните: паттерны — это инструменты, а не догмы. Выбирайте их осознанно, исходя