Skip to content

Instantly share code, notes, and snippets.

@kumabook
Last active March 12, 2022 06:47
Show Gist options
  • Save kumabook/56f6a349789e7215d114 to your computer and use it in GitHub Desktop.
Save kumabook/56f6a349789e7215d114 to your computer and use it in GitHub Desktop.
Observer pattern with swift protocol extension
import Foundation
public protocol Observer: Equatable {
associatedtype EventType
func listen(_ event: EventType)
}
public protocol Observable {
associatedtype ObserverType: Observer
associatedtype EventType
var observers: [ObserverType] { get set }
mutating func addObserver(_ observer: ObserverType)
mutating func removeObserver(_ observer: ObserverType)
func notify(_ event: EventType)
}
extension Observable where EventType == ObserverType.EventType {
mutating public func addObserver(_ observer: ObserverType) {
var os = observers
os.append(observer)
observers = os
}
mutating public func removeObserver(_ observer: ObserverType) {
guard let i = observers.firstIndex(of: observer) else { return }
observers.remove(at: i)
}
public func notify(_ event: EventType) {
for o in observers {
o.listen(event)
}
}
}
public enum News {
case morning(String, Publisher)
case noon (String, Publisher)
case evening(String, Publisher)
case extra (String, Publisher)
}
public struct Subscriber: Observer, Equatable {
public typealias EventType = News
public var id: String
public var name: String
public func listen(_ event: EventType) {
switch event {
case .morning(let content, var publisher): read(content: content, publisher: &publisher)
case .noon (let content, var publisher): read(content: content, publisher: &publisher)
case .evening(let content, var publisher): read(content: content, publisher: &publisher)
case .extra (let content, var publisher): read(content: content, publisher: &publisher)
}
}
public func read(content: String, publisher: inout Publisher) {
print("\(name) reads morning paper: \(content)\n")
if content.contains(name) {
publisher.removeObserver(self)
print("\(name) unsubscribed\n")
}
}
}
public func ==(lhs: Subscriber, rhs: Subscriber) -> Bool {
return lhs.id == rhs.id
}
public class Publisher: Observable {
public var name: String
public typealias ObserverType = Subscriber
public typealias EventType = News
private var _observers: [ObserverType] = []
public var observers: [ObserverType] {
get { return _observers }
set { _observers = newValue }
}
public init(name: String) {
self.name = name
}
}
var sentence_spring = Publisher(name: "Bunshun")
var kiyo = Subscriber(id: "kiyo" , name: "Kiyo")
var kimutaku = Subscriber(id: "kimura" , name: "Kimutaku")
var nakai = Subscriber(id: "nakai" , name: "Nakai")
var yoshiki = Subscriber(id: "yoshiki", name: "yoshiki")
sentence_spring.addObserver(kimutaku)
sentence_spring.addObserver(nakai)
sentence_spring.addObserver(kiyo)
sentence_spring.addObserver(yoshiki)
sentence_spring.notify(.morning("Becky and GESU NO KIWAMI are in inappropriate relationship!!!", sentence_spring))
sentence_spring.removeObserver(nakai)
sentence_spring.removeObserver(kimutaku)
sentence_spring.notify(.evening("SMAP will be broken up!?" , sentence_spring))
sentence_spring.notify(.extra ("Kiyo is arrested!!" , sentence_spring))
sentence_spring.notify(.extra ("Sean K is pure japanease!!", sentence_spring))
@MrSkwiggs
Copy link

Thanks for the snippet. Just a quick comment though; your protocols are using typealias when they should use associatedtype instead.

@kumabook
Copy link
Author

kumabook commented Jul 4, 2019

@MrSkwiggs

Migrated to swift 5!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment