Вызовите метод на всех существующих экземплярах UIViewController - PullRequest
0 голосов
/ 02 сентября 2018

Я хочу иметь возможность разрешить пользователю изменять некоторые свойства графического интерфейса пользователя сразу через все приложение. Чтобы достичь этого, я подумал о создании протокола вроде

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 голосов
/ 02 сентября 2018

Вы можете сделать это с центральным диспетчером, и каждый 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().

0 голосов
/ 02 сентября 2018

Вы можете использовать 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 до iOS 9, обязательно удалите наблюдателя в deinit.)

И чтобы опубликовать уведомление, когда вы хотите инициировать изменение:

NotificationCenter.default.post(name: .changeViewProperties, object: nil)
0 голосов
/ 02 сентября 2018

Вы можете получить доступ к корневому контроллеру приложения с помощью:

UIApplication.shared.keyWindow.rootViewController

Конечно, предполагается, что текущее окно ключа - это окно с корневым контроллером вашего приложения.

Вы также можете получить доступ к свойству window вашего делегата приложения и получить rootViewController из этого окна.

Ваш общий подход действителен. Нет другого «более элегантного» способа обойти текущие контроллеры представления вашего приложения. Хотя вы должны также просмотреть представленные контроллеры представления, а также дочерние контроллеры представления.

Однако более простым решением может быть отправка уведомления с использованием NotificationCenter, и все ваши контроллеры представления будут реагировать соответствующим образом.

...