[Разработка под iOS, Xcode, Swift] Паттерн Observer в Swift

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
26-Июн-2021 16:33


Всем доброго времени суток! В этой статье речь пойдет о паттерне Observer. Все, кто связан с iOS разработкой наверняка сталкивались с инструментами в основе работы которых лежит этот паттерн. Например, NotificationCenter, KVO или великий и могучий RxSwift, который сейчас очень популярен. В этой статье я на простом примере разберу принцип работы данного паттерна. Не ругайтесь, перфекционисты! Эта статья исключительно про паттерн Observer, поэтому для большей наглядности некоторыми принципами код стайла пришлось пренебречь. Пример из жизниДопустим, при просмотре Youtube вы наткнулись на интересный контент и захотели подписаться на этого автора. Вы нажимаете кнопку Subscribe и вуаля! Вы не пропустите ни одного нового видео от понравившегося вам автора. Принцип работы паттерна точно такой же. Есть наблюдаемая сущность, и есть те, кто подписываются на ее изменения - подписчики. Причем подписчики мгновенно узнают об изменениях. Перейдем от теории к практике.Создаем новый проект. 
Интерфейс выбираем Storyboard, писать будем на Swift.
Открываем файл Main.storyboard
Главный экран будет состоять из двух основных секций: "модуль блогера", с кнопкой при помощи которой он публикует контент и "модуль подписчика", где подписчик видит самое свежее видео от автора, а также может отписаться или подписаться на автора. Итого на сториборд помещаем 4xUILabel, 1XUIButton, 1xUISwitch. Черным цветом указаны UILabel, синим цветом UIButton.
Делаем шрифт пожирнее и устанавливаем констрейнты.
Протягиваем связи от всех элементов кроме заголовков. При зажатой клавише Option нажимаем на ViewController. Отрывается второе окно. При зажатой клавише перетаскиваем связи во ViewController. В итоге должно получиться как на рисунке ниже.
Со сторибордами все, осталось написать код. Создаем протокол подписчика, это наш Observer.
protocol Subscriber : AnyObject {
    func update(subject : Bloger )
}
Создаем класс Bloger. В нем указываем переменные которые будут хранить последнюю актуальную информацию для наших подписчиков. В нашем случае это название последнего видео и его порядковый номер.
class Bloger {
    var counter : Int = 0
    var lastVideo = ""
}
 Также, класс должен содержать список подписчиков.
private lazy var subscribers : [Subscriber] = []
Метод, который выполняет подписки на наблюдаемый объект.
func subscribe(_ subscriber: Subscriber) {
        print("subscribed")
        subscribers.append(subscriber)
    }
Метод, который служит для отмены подписки. Логика этого метода в том, что совершается поиск по массиву нужного нам объекта, затем объект из него удаляется.
func unsubscribe(_ subscriber: Subscriber) {
        if let index = subscribers.firstIndex(where: {$0 === subscriber}) {
            subscribers.remove(at: index)
        }
        print("unsubscribed")
    }
Метод для рассылки уведомлений подписчикам:
func notify() {
        subscribers.forEach { $0.update(subject: self)
        }
    }
Метод для рассылки уведомлений подписчикам:
func notify() {
        subscribers.forEach { $0.update(subject: self)
        }
    }
Ну и напоследок метод, который содержит в себе определенную бизнес логику. В нашем случае это публикация видео от автора и увеличение его номера на единицу с каждым последующим вызовом этого метода.
func releaseVideo() {
        counter += 1
        lastVideo = "video" + "\(counter)"
        notify() //Notify subscribers
        print("released!")
    }
В итоге у нас получается:
class Bloger {
    var counter : Int = 0
    var lastVideo = ""
    private lazy var subscribers : [Subscriber] = [] // Создаем массив с подписчиками
    func subscribe(_ subscriber: Subscriber) {
        print("subscribed")
        subscribers.append(subscriber)
    }
    func unsubscribe(_ subscriber: Subscriber) {
        print("unsubscribed")
        if let index = subscribers.firstIndex(where: {$0 === subscriber}) {
            subscribers.remove(at: index)
        }
    }
    func notify() {
        subscribers.forEach { $0.update(subject: self)
        }
    }
    func releaseVideo() {
        counter += 1
        lastVideo = "video" + "\(counter)"
        notify()
        print("released!")
    }
}
Осталось совсем чуть-чуть. Подписываем наш ViewController на протокол Subscriber.
В этом методе мы будем обновлять Label на экране, который показывает название последнего полученного видео от блогера.
func update(subject: Bloger) {
        subscriberInfoLabel.text = subject.lastVideo
    }
Создаем экземпляр класса Bloger() .
let bloger = Bloger()
В методе ViewDidLoad подписываемся на этот экземпляр.
bloger.subscribe(self)
Чтобы все заработало, осталось привязать методы для подписки и публикации к нашему интерфейсу. Для этого пропишем следующий код:
@IBAction func publishButton(_ sender: Any) {
        bloger.releaseVideo()
    }
@IBAction func subscribeToggle(_ sender: Any) {
        if (sender as AnyObject).isOn {
            bloger.subscribe(self)
        } else {
            bloger.unsubscribe(self)
        }
    }
В итоге у нас получается вот такой код:
import UIKit
class ViewController: UIViewController, Subscriber {
    @IBOutlet weak var subscriberInfoLabel: UILabel!
    let bloger = Bloger()
    override func viewDidLoad() {
        super.viewDidLoad()
        bloger.subscribe(self)
    }
    @IBAction func publishButton(_ sender: Any) {
        bloger.releaseVideo()
    }
    @IBAction func subscribeToggle(_ sender: Any) {
        if (sender as AnyObject).isOn {
            bloger.subscribe(self)
        } else {
            bloger.unsubscribe(self)
        }
    }
    func update(subject: Bloger) {
        subscriberInfoLabel.text = subject.lastVideo
    }
}
//MARK:- Protocols
protocol Subscriber : AnyObject {
    func update(subject : Bloger )
}
class Bloger {
    var counter : Int = 0
    var lastVideo = ""
    private lazy var subscribers : [Subscriber] = [] // Создаем массив с подписчиками
    func subscribe(_ subscriber: Subscriber) {
        print("subscribed")
        subscribers.append(subscriber)
    }
    func unsubscribe(_ subscriber: Subscriber) {
        print("unsubscribed")
        if let index = subscribers.firstIndex(where: {$0 === subscriber}) {
            subscribers.remove(at: index)
        }
    }
    func notify() {
        subscribers.forEach { $0.update(subject: self)
        }
    }
    func releaseVideo() {
        counter += 1
        lastVideo = "video" + "\(counter)"
        notify()
        print("released!")
    }
}
Запускаем симулятор и проверяем, что вышло!
Надеюсь, теперь вы разобрались с основой работы паттерна Observer, и статья была вам полезна! Ссылка на итоговый проект
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_razrabotka_pod_ios (Разработка под iOS), #_xcode, #_swift, #_observer_pattern, #_design_patterns, #_swift, #_ios, #_xcode, #_razrabotka_pod_ios (
Разработка под iOS
)
, #_xcode, #_swift
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 19:51
Часовой пояс: UTC + 5