如何在Swift的另一个屏幕上收听更新?

时间:2018-03-20 00:42:07

标签: ios swift

首先看看GIF:

enter image description here

第二页正在收听第一页上的操作。首先,第二页有状态:counter = 2language = Chinese。但是当在第一页上按下按钮时,第二页的状态会更新。

我正在使用名为ReSwift的模块,如果您熟悉redux,则它是redux的Swift版本。但是,我想知道如何在不使用此模块的情况下完成此操作。 (我不会问如何确切地了解GIF中发生的事情,但总的来说listen to updates/events on another page因此,我希望没有" hacky"解决方案)。

如果您对ReSwift方式感兴趣,请参阅以下代码

以下内容与此问题无关

Language.swift:

enum Language {
    case English
    case Chinese
}

LanguageState.swift:

import ReSwift

struct LanguageState: StateType {
    var language: Language = .English
}

CounterState.swift:

import ReSwift

struct CounterState: StateType {
    var counter: Int = 0
}

AppState.swift:

import ReSwift

struct AppState: StateType {
    var counterState: CounterState = CounterState()
    var languageState: LanguageState = LanguageState()
}

Actions.swift:

import ReSwift

struct CounterActionIncrease: Action {}
struct CounterActionDecrease: Action {}
struct ChangeLanguageToEnglish: Action {}
struct ChangeLanguageToChinese: Action {}

LanguageReducer.swift:

import ReSwift

func LanguageReducer(action: Action, state: LanguageState?) -> LanguageState {
    var state = state ?? LanguageState()

    switch action {
    case _ as ChangeLanguageToEnglish:
        state.language = .English
    case _ as ChangeLanguageToChinese:
        state.language = .Chinese
    default:
        break
    }

    return state
}

CounterReducer.swift:

import ReSwift

func CounterReducer(action: Action, state: CounterState?) -> CounterState {
    var state = state ?? CounterState()

    switch action {
    case _ as CounterActionIncrease:
        state.counter += 1
    case _ as CounterActionDecrease:
        state.counter -= 1
    default:
        break
    }

    return state
}

AppReducer.swift:

import ReSwift

func AppReducer(action: Action, state: AppState?) -> AppState {
    return AppState(
        counterState: CounterReducer(action: action, state: state?.counterState),
        languageState: LanguageReducer(action: action, state: state?.languageState)
    )
}

然后,在AppDelegate.swift

import UIKit
import ReSwift

let store = Store<AppState>(reducer: AppReducer, state: nil)
...
...

最后,您可以以标准方式订阅ViewControllers商店

3 个答案:

答案 0 :(得分:2)

只需将其插入Xcode游乐场即可查看其机械工作原理。如果它打印&#34; Slick daddy&#34;然后它就联系起来了。可能需要进行大量的微调,例如确保您只更新已更改的数据,但是,如果代表模式不是您的选择,则使用观察者是一个很好的选择。

class ControllerA {

    // use a data model for the view controller
    let dataModel = "Slick daddy"

    init() {
        postNoti()
    }

    // whenever a change is made, first update the data model and
    // then post a notification and attach the data model object
    func postNoti() {
        NotificationCenter.default.post(name: Notification.Name("slickDaddy"), object: dataModel)
    }

}

class ControllerB {

    init() {
        addObserver()
    }

    // add an observer for that notification
    func addObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(notificationHandler(_:)), name: Notification.Name("slickDaddy"), object: nil)
    }

    // handle the notification using the data model and make
    // the changes to the current controller
    @objc func notificationHandler(_ sender: Notification) {
        guard let model = sender.object else {
            return
        }
        print(model) // verifies it works
    }

}

let b = ControllerB()
let a = ControllerA()

// prints "Slick daddy"

答案 1 :(得分:1)

您可以使用NotificationCenter来实现这一目标。首先,我们必须创建一个单例类,并创建一个全局变量didUpdateNotificationName,我们将用它来发布事件并订阅事件:

let didUpdateDataNotificationName = "didUpdateDataNotificationName"

class AppState {

    static var shared = AppState()

    private init(){
        self.counter = 0
        self.language = "English"
    }

    private (set) var counter: Int {
        didSet {
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: didUpdateDataNotificationName), object: nil)
        }
    }
    private (set) var language: String {
        didSet {
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: didUpdateDataNotificationName), object: nil)
        }
    }

    func update(counter: Int){
        self.counter = counter
    }

    func update(language: String){
        self.language = language
    }

}

之后,在每个UIViewController上,您可以添加更新的侦听器:

NotificationCenter.default.addObserver(
    self, 
    selector: #selector(updateView), 
    name: NSNotification.Name(rawValue: didUpdateDataNotificationName),
    object: nil)

同时确保实现将在每个通知上执行的方法,在我们的案例中updateView

@objc func updateView(){
    label.text = "\(DataModel.shared.counter) \(DataModel.shared.language)"

}

现在,每次更新AppState类中的变量时,都会向所有观察者发送通知。

一个非常重要的注意事项是,当您处理通知时,应该在不再需要时删除观察者。例如,在您班级的deinit方法中:

deinit {
    NotificationCenter.default.removeObserver(
        self, 
        name: NSNotification.Name(rawValue: didUpdateDataNotificationName),
        object: self)
}

答案 2 :(得分:0)

如果是UITabBarController,您只需使用以下代码即可访问FirtsViewController中的SecondViewController

var svc:SecondViewController = self.tabBarController.viewControllers[1] as SecondViewController!