Good day! This article will focus on the Observer pattern. Everyone involved in iOS development has probably come across tools that are based on this pattern. For example, NotificationCenter, KVO or the great and mighty RxSwift, which is very popular right now. In this article, I will use a simple example to analyze how this pattern works. Don't swear, perfectionists! This article is exclusively about the Observer pattern, so for greater clarity, some of the principles of the code style had to be neglected.
Real life example
, 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 = ""
}
, . Subscriber, retain cycle , , . , , Subscriber :
//Fix retain cycle
struct WeakSubscriber {
weak var value : Subscriber?
}
class Bloger {
private lazy var subscribers : [WeakSubscriber] = [] //
}
, .
func subscribe(_ subscriber: Subscriber) {
print("subscribed")
subscribers.append(WeakSubscriber(value: subscriber))
}
, . , , . , .
func unsubscribe(_ subscriber: Subscriber) {
subscribers.removeAll(where: { $0.value === subscriber })
print("unsubscribed")
}
:
func notify() {
subscribers.forEach { $0.value?.update(subject: self)
}
}
, . .
func releaseVideo() {
counter += 1
lastVideo = "video" + "\(counter)"
notify() //Notify subscribers
print("released!")
}
:
//Fix retain cycle
struct WeakSubscriber {
weak var value : Subscriber?
}
class Bloger {
private lazy var subscribers : [WeakSubscriber] = [] //
var counter : Int = 0
var lastVideo = ""
func subscribe(_ subscriber: Subscriber) {
print("subscribed")
subscribers.append(WeakSubscriber(value: subscriber))
}
func unsubscribe(_ subscriber: Subscriber) {
subscribers.removeAll(where: { $0.value === subscriber })
print("unsubscribed")
}
func notify() {
subscribers.forEach { $0.value?.update(subject: self)
}
}
func releaseVideo() {
counter += 1
lastVideo = "video" + "\(counter)"
notify()
print("released!")
}
}
-. Subscriber ViewController.
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!
var 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 : UIViewController {
func update(subject : Bloger )
}
//Fix retain cycle
sruct WeakSubscriber {
weak var value : Subscriber?
}
class Bloger {
private lazy var subscribers : [WeakSubscriber] = [] //
var counter : Int = 0
var lastVideo = ""
func subscribe(_ subscriber: Subscriber) {
print("subscribed")
subscribers.append(WeakSubscriber(value: subscriber))
}
func unsubscribe(_ subscriber: Subscriber) {
subscribers.removeAll(where: { $0.value === subscriber })
print("unsubscribed")
}
func notify() {
subscribers.forEach { $0.value?.update(subject: self)
}
}
func releaseVideo() {
counter += 1
lastVideo = "video" + "\(counter)"
notify()
print("released!")
}
}
, !
, Observer, !