I implemented an observer pattern in the below code. However, I am not sure how to create SeasonSubject class's instance in order to call addObserver() function? I don't want to create it inside my view controller. Please refer to below code.
//
// SeasonViewController.swift
// PhotoCalender
//
// Created by Suraj M Gaikwad on 09/07/21.
//
import UIKit
enum Season: String {
case summer
case winter
case monsoon
case none
}
protocol SeasonObserver {
func onSeasonChange(_season: Season)
}
class PhotoframeObserver: SeasonObserver {
var delegate: SeasonViewControllerDelegate?
init(_delegate: SeasonViewControllerDelegate) {
delegate = _delegate
}
func onSeasonChange(_season: Season) {
switch _season {
case .monsoon, .summer, .winter:
delegate?.changeTheLayoutPer(_season: _season)
case .none:
debugPrint("none")
}
}
}
class PhotoDetailsObserver: SeasonObserver {
var delegate: SeasonViewControllerDelegate?
init(_delegate: SeasonViewControllerDelegate) {
delegate = _delegate
}
func onSeasonChange(_season: Season) {
switch _season {
case .monsoon, .summer, .winter:
delegate?.changeTheTitle(_season: _season)
case .none:
debugPrint("none")
}
}
}
protocol SeasonSubjectProtocol {
func informTheSeasonChange(_season: Season)
}
class SeasonSubject: SeasonSubjectProtocol {
private var _season = Season.none
var changedSeason: Season {
get {
_season
}
set {
_season = newValue
}
}
private var seasonObserver = [SeasonObserver]()
func addObserver(_observer: SeasonObserver) {
seasonObserver.append(_observer)
}
func removeObserver(_observer: SeasonObserver) {
// seasonObserver.remove(at: 0)
}
private func notifyObserver() {
seasonObserver.forEach { $0.onSeasonChange(_season: _season)
}
}
func informTheSeasonChange(_season: Season) {
changedSeason = _season
}
deinit {
seasonObserver.removeAll()
}
}
protocol SeasonViewControllerDelegate {
func changeTheLayoutPer(_season: Season)
func changeTheTitle(_season: Season)
}
class SeasonViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var backgroundView: UIView!
@IBOutlet weak var seasonTitle: UILabel!
var delegate: SeasonSubjectProtocol?
var count = 0
override func viewDidLoad() {
super.viewDidLoad()
self.imageView.image = UIImage()
self.backgroundView.backgroundColor = .white
self.seasonTitle.text = "none"
}
@IBAction func changeTheSeason(_ sender: UIButton) {
if count > 2 {
count = 0
return
}
if count == 0 {
delegate?.informTheSeasonChange(_season: Season.summer)
}
if count == 1 {
delegate?.informTheSeasonChange(_season: Season.winter)
}
if count == 2 {
delegate?.informTheSeasonChange(_season: Season.monsoon)
}
count += 1
}
}
extension SeasonViewController: SeasonViewControllerDelegate {
func changeTheLayoutPer(_season: Season) {
switch _season {
case .monsoon:
self.imageView.image = UIImage()
self.backgroundView.backgroundColor = .gray
case .summer:
self.imageView.image = UIImage()
self.backgroundView.backgroundColor = .orange
case .winter:
self.imageView.image = UIImage()
self.backgroundView.backgroundColor = .blue
case .none:
debugPrint("none")
self.imageView.image = UIImage()
self.backgroundView.backgroundColor = .white
}
}
func changeTheTitle(_season: Season) {
switch _season {
case .monsoon, .summer, .winter, .none:
self.seasonTitle.text = _season.rawValue
}
}
}
I want to create an instance of SeasonSubject() class. I want to call addObserver & removeObserver() methods.
You can create SeasonSubject
as a singleton instance, it already maintains an array of observers so multiple observers can use this same instance throughout the app.
class SeasonSubject: SeasonSubjectProtocol {
static let shared = SeasonSubject()
}
All you need to do now is - call addObserver
/ removeObserver
on this singleton instance from the places you want.
class ViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
SeasonSubject.shared.addObserver(self)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
SeasonSubject.shared.removeObserver(self)
}
}
CAUTION : You must make sure these add/remove calls are balanced otherwise you will fall into the trap of observers never getting deallocated.
If you want to stay away from this problem - you should consider a NotificationCenter
based implementation where your observers are never at risk of being retained in memory forever.