我希望能够允许用户立即通过所有应用程序更改图形用户界面的某些属性。为了实现这一目标,我想创建一个类似的协议。
protocol MyProtocol {
func changeProperties()
}
因此,每个 UIViewController 都可以以自己的方式更改这些属性,然后在所有当前实例化的控制器中调用此方法。
但是,我不知道这是否可能。我的第一个想法是访问应用程序的最根控制器,然后循环访问所有递归调用该方法的子控制器。类似的东西
func updatePropertiesFrom(_ vc: UIViewController) {
for child in vc.childViewControllers {
if let target = child as? MyProtocol {
target.changeProperties()
}
updatePropertiesFrom(child)
}
}
let appRootController = ...
updatePropertiesFrom(appRootController)
我不知道如何获得那个appRootController,我想知道是否有更优雅的方法可以做到这一点。谢谢。
您可以使用NotificationCenter
. 例如,定义通知名称:
extension Notification.Name {
static let changeViewProperties = Notification.Name(Bundle.main.bundleIdentifier! + ".changeViewProperties")
}
然后,您的各种视图控制器可以注册,以便在发布此通知时收到通知:
NotificationCenter.default.addObserver(forName: .changeViewProperties, object: nil, queue: .main) { _ in
// do something here
}
(如果您支持 iOS 9 之前的 iOS 版本,请确保在deinit
中删除您的观察器。
要在要启动更改时发布通知,请执行以下操作:
NotificationCenter.default.post(name: .changeViewProperties, object: nil)
您可以使用以下命令访问应用的根控制器:
UIApplication.shared.keyWindow.rootViewController
当然,这假设当前密钥窗口是具有应用根控制器的窗口。
还可以访问应用委托的window
属性,并从该窗口中获取rootViewController
。
您的一般方法是有效的。没有其他"更优雅"的方式来遍历应用的当前视图控制器。尽管您还应该遍历呈现的视图控制器以及子视图控制器。
但是,更简单的解决方案可能是使用NotificationCenter
发布通知,并让所有视图控制器做出相应的响应。
您可以使用中央调度程序执行此操作,并让每个UIViewController
向其注册。
例:
class MyDispatcher{
static let sharedInstance = MyDispatcher()
var listeners: [MyProtocol]()
private init() {}
public func dispatch(){
for listener in listeners{
listener.changeProperties()
}
}
}
从要更新属性的每个UIViewController
中,调用MyDispatcher.sharedInstance.listeners.append(self)
。如果要更新属性,请调用MyDispatcher.sharedInstance.dispatch()
。