I'm trying to use delegate and protocol first time.
I want to change the theme across many view controller.
Then on any controller which has protocol to change theme
When I go to this controller now I expect theme to be new but is old.
I do not go from theme controller to where them has changed
My code
protocol ThemeDelegate: class {
func changeTheme(theme: UIColor)
}
class FirstController: UICollectionViewController, UICollectionViewDelegateFlowLayout, ThemeDelegate {
var newTheme: UIColor = .red
func changeTheme(theme: UIColor) {
newTheme = theme
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = newTheme
}
}
ThemeController {
weak var themeDelegate: ThemeDelegate?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let theme = .blue
themeDelegate?.changeTheme(theme: theme)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: themeCellId, for: indexPath) as! ThemeCell
cell.themeImageView.image = UIImage(named: "theme cell image")
return cell
}
}
this is order
image2
I'll try to make it simple:-
1) First, declare a protocol:-
protocol ThemeDelegate{
func changeTheme(theme: String, fontColor: UIColor, alpha: CGFloat)
}
2) Have a variable of that protocol in your ThemeController:
open var themeDelegate: ThemeDelegate? = nil
3) Call the delegate functions through themeDelegate
:- (you've done this right till this step)
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
themeDelegate?.changeTheme(theme: theme, fontColor: fontColor, alpha: alpha)
}
4) You need to conform your AnyController
as the delegate, like yourThemeControllerInstance.delegate = self
and you've done that as well.
It doesn't work because you've declared a new instance of ThemeController
and have conformed AnyController
to be the delegate of that new instance which supposedly has the same old theme:
override func viewDidLoad() {
let themeController = ThemeController() // This is a new instance which you have created, so gets initialised with old theme. You have made your class to be the delegate of this instance
themeController.themeDelegate = self
}
In order for your delegate to work as expected, you need the same instance of ThemeController
where you change your theme
You can set delegate but careful view needs a be load.
You do this also with notifications and send all viewControllers with conforms Theme
1 - Your Step
import UIKit
protocol ThemeDelegate: class {
func changeTheme(theme: String, fontColor: UIColor, alpha: CGFloat)
}
class ThemeController: UIViewController {
weak var themeDelegate: ThemeDelegate?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
themeDelegate?.changeTheme(theme: theme, fontColor: fontColor, alpha: alpha)
}
}
class XViewController: UIViewController {
// Create an instance
lazy var themeController = ThemeController()
override func viewDidLoad() {
super.viewDidLoad()
// We need call loadView becase collectionView needs to be show
themeController.loadView()
themeController.themeDelegate = self
}
}
extension XViewController: ThemeDelegate {
// And we conform ThemeDelegate
func changeTheme(theme: String, fontColor: UIColor, alpha: CGFloat) {
// TODO UI
}
}
2 - Observer Step
// Sometimes we need update multiple viewControllers and we should use notification and observers
// We create a model
struct Theme {
let theme: String
let fontColor: UIColor
let alpha: CGFloat
}
// We need a protocol for we don't want all view controller listen theme
protocol Themeable: class {
func listenTheme()
func didThemeChange(theme: Theme)
}
// Global notification name
let themeableNotificationName = Notification.Name(rawValue: "ThemeableNotification")
// Our protocol extension and observer notification
extension Themeable where Self: UIViewController {
func listenTheme() {
NotificationCenter.default.addObserver(forName: themeableNotificationName, object: nil, queue: nil) { [weak self] notification in
guard let theme = notification.object as? Theme else { return }
self?.didThemeChange(theme: theme)
}
}
}
// Notification sender themeController
class NotifyThemeController: UIViewController {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// Create a model and post
NotificationCenter.default.post(name: themeableNotificationName, object: Theme(theme: "Lorem", fontColor: .red, alpha: 1.0), userInfo: nil)
}
}
// YViewController
class YViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// We need call this method for observer
listenTheme()
}
}
// YViewController conforms Themeable
extension YViewController: Themeable {
func didThemeChange(theme: Theme) {
// TODO UI
}
}
// ZViewController
class ZViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// We need call this method for observer
listenTheme()
}
}
// ZViewController conforms Themeable
extension ZViewController: Themeable {
func didThemeChange(theme: Theme) {
// TODO UI
}
}
Have Fun!