swift - 观察者沟通模式
问题描述
我有一个非常简单的实现(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
,它就会加载该视图控制器。
您可以通过在of 中添加print
声明来验证这一点。viewDidLoad
SecondVC
您还可以验证,如果您在返回并按下SecondVC
之前导航到,则在这种情况下,两个视图控制器都会收到通知。ViewController
Notify
所以,这不是一个错误——它只是加载视图时的一个实现细节。
如果您想找到一种方法来确保SecondVC
在加载时可以访问该信息,您有两种选择:
- 依靠不同的传播状态的系统
- 将您的通知侦听器放入
required init?(coder: NSCoder)
而不是viewDidLoad
(在设置期间确实会调用它)。但这有一个警告:UILabel
还不会加载,因此您必须存储该状态以供以后加载。mySecondLabel
之前尝试访问viewDidLoad
会导致崩溃。
如果您要使用该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"
}
}
推荐阅读
- php - 更改电子邮件上的 WooCommerce 电话号码链接
- java - 使用 Jackson 将 YAML 反序列化为 Java 对象时在新行中保留缩进
- python - 你可以在 Numpy 中制作多小的 DataType?
- jquery - jquery自动完成文本输入美国州每个州去不同的页面不区分大小写
- c++ - 如何在 C/C++ 10.5 章节数值配方中调用** var
- python - 在字符矩阵中递归搜索单词
- android - Android 测试 GitHub 操作:没有这样的文件或目录,打开 'undefined/licenses/android-sdk-arm-dbt-license'
- python-3.x - 在字典中附加一个 int 键
- c++ - c++ 中双精度(与长双精度)的相等(==)
- typescript - 从其他项目文件导入类时,Monorepo 避免(找不到模块“lib”)