在所有现有的UIViewController实例上调用方法

时间:2018-09-02 15:27:27

标签: ios swift uiviewcontroller protocols

我希望能够允许用户通过所有应用程序立即更改图形用户界面的某些属性。为此,我考虑过创建类似

的协议
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,我想知道是否还有其他更优雅的方法可以做到这一点。谢谢。

3 个答案:

答案 0 :(得分:1)

您可以使用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)

答案 1 :(得分:0)

您可以通过以下方式访问应用的根控制器:

UIApplication.shared.keyWindow.rootViewController

当然,这假定当前的密钥窗口是应用程序的根控制器所在的窗口。

您还可以访问应用程序委托的window属性,并从该窗口获取rootViewController

您的一般方法是有效的。没有其他“更优雅”的方法来遍历应用程序的当前视图控制器。尽管您还应该遍历所提供的视图控制器以及子视图控制器。

但是,一种更简单的解决方案是使用NotificationCenter发布通知,并使所有视图控制器做出相应的响应。

答案 2 :(得分:0)

您可以使用中央调度程序来完成此操作,并让每个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()