观察者通信模式
Observer Communication Pattern
我有一个非常简单的实现 (3 类) 来获取基础知识。但是有BUG。
事实:它通知 ViewController,但它没有通知 SecondVC 的屏幕。想知道为什么或在哪里!
Git: https://github.com/marlhex/ObserverPattern
相关类:
struct MyNotifications {
static let broadcast = "BROADCAST"
}
import UIKit
let notificationCtr = NotificationCenter.default
class ViewController: UIViewController {
@IBOutlet weak var myLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
notificationCtr.addObserver(self, selector: #selector(notifyObservers), name: NSNotification.Name(rawValue: MyNotifications.broadcast), object: nil)
}
@objc func notifyObservers() {
myLabel.text = "I got Notified"
}
@IBAction func doBroadcast(_ sender: Any) {
notificationCtr.post(name: NSNotification.Name(rawValue: MyNotifications.broadcast), object: self)
}
}
import UIKit
class SecondVC: UIViewController {
@IBOutlet weak var mySecondLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
notificationCtr.addObserver(self, selector: #selector(notifyObserverstoo), name: NSNotification.Name(rawValue: MyNotifications.broadcast), object: nil)
}
@objc func notifyObserverstoo() {
mySecondLabel.text = "I got Notified too" //Bug only notifies one view controller
}
}
您正在使用 UITabBarController 来托管视图。系统最初只加载它需要显示的视图控制器(在本例中为 ViewController
)。然后,一旦您单击 SecondVC
的选项卡,它就会加载该视图控制器。
您可以通过在 SecondVC
的 viewDidLoad
中放置一个 print
语句来验证这一点。
您还可以验证如果在返回 ViewController
并按 Notify
之前导航到 SecondVC
,在这种情况下两个视图控制器都会收到通知。
所以,这不是错误 -- 它只是加载视图时的实现细节。
如果您想找到一种方法来确保 SecondVC
在加载时可以访问该信息,您有两个选择:
- 依靠不同的系统传播状态
- 将您的通知侦听器放在
required init?(coder: NSCoder)
而不是 viewDidLoad
中(这会在设置过程中调用)。 这里有一个警告:UILabel
尚未加载,因此您必须存储该状态以便稍后加载。在 viewDidLoad
之前尝试访问 mySecondLabel
将导致崩溃。
更新
更新了在您要使用 init
方法的事件中存储通知的代码:
class SecondVC: UIViewController {
// MARK: - Properties
@IBOutlet weak var mySecondLabel: UILabel?
var haveBeenNotified = false //to store whether the notification has been seen
required init?(coder: NSCoder) {
super.init(coder: coder)
notificationCtr.addObserver(self, selector: #selector(notifyObserverstoo), name: NSNotification.Name(rawValue: MyNotifications.broadcast), object: nil)
}
// MARK: - Life Cycle Methods
override func viewDidLoad() {
super.viewDidLoad()
print("Loaded second view controller")
if haveBeenNotified {
mySecondLabel?.text = "Was notified before viewDidLoad"
}
}
// MARK: - Observer Selector Functions
@objc func notifyObserverstoo() {
haveBeenNotified = true
mySecondLabel?.text = "I got Notified too"
}
}
我有一个非常简单的实现 (3 类) 来获取基础知识。但是有BUG。
事实:它通知 ViewController,但它没有通知 SecondVC 的屏幕。想知道为什么或在哪里!
Git: https://github.com/marlhex/ObserverPattern
相关类:
struct MyNotifications {
static let broadcast = "BROADCAST"
}
import UIKit
let notificationCtr = NotificationCenter.default
class ViewController: UIViewController {
@IBOutlet weak var myLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
notificationCtr.addObserver(self, selector: #selector(notifyObservers), name: NSNotification.Name(rawValue: MyNotifications.broadcast), object: nil)
}
@objc func notifyObservers() {
myLabel.text = "I got Notified"
}
@IBAction func doBroadcast(_ sender: Any) {
notificationCtr.post(name: NSNotification.Name(rawValue: MyNotifications.broadcast), object: self)
}
}
import UIKit
class SecondVC: UIViewController {
@IBOutlet weak var mySecondLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
notificationCtr.addObserver(self, selector: #selector(notifyObserverstoo), name: NSNotification.Name(rawValue: MyNotifications.broadcast), object: nil)
}
@objc func notifyObserverstoo() {
mySecondLabel.text = "I got Notified too" //Bug only notifies one view controller
}
}
您正在使用 UITabBarController 来托管视图。系统最初只加载它需要显示的视图控制器(在本例中为 ViewController
)。然后,一旦您单击 SecondVC
的选项卡,它就会加载该视图控制器。
您可以通过在 SecondVC
的 viewDidLoad
中放置一个 print
语句来验证这一点。
您还可以验证如果在返回 ViewController
并按 Notify
之前导航到 SecondVC
,在这种情况下两个视图控制器都会收到通知。
所以,这不是错误 -- 它只是加载视图时的实现细节。
如果您想找到一种方法来确保 SecondVC
在加载时可以访问该信息,您有两个选择:
- 依靠不同的系统传播状态
- 将您的通知侦听器放在
required init?(coder: NSCoder)
而不是viewDidLoad
中(这会在设置过程中调用)。 这里有一个警告:UILabel
尚未加载,因此您必须存储该状态以便稍后加载。在viewDidLoad
之前尝试访问mySecondLabel
将导致崩溃。
更新
更新了在您要使用 init
方法的事件中存储通知的代码:
class SecondVC: UIViewController {
// MARK: - Properties
@IBOutlet weak var mySecondLabel: UILabel?
var haveBeenNotified = false //to store whether the notification has been seen
required init?(coder: NSCoder) {
super.init(coder: coder)
notificationCtr.addObserver(self, selector: #selector(notifyObserverstoo), name: NSNotification.Name(rawValue: MyNotifications.broadcast), object: nil)
}
// MARK: - Life Cycle Methods
override func viewDidLoad() {
super.viewDidLoad()
print("Loaded second view controller")
if haveBeenNotified {
mySecondLabel?.text = "Was notified before viewDidLoad"
}
}
// MARK: - Observer Selector Functions
@objc func notifyObserverstoo() {
haveBeenNotified = true
mySecondLabel?.text = "I got Notified too"
}
}