【问题标题】:Force child view controllers to call a base view controller method强制子视图控制器调用基本视图控制器方法
【发布时间】:2019-10-18 10:07:02
【问题描述】:

我需要在我的每个 ViewController 的 viewDidLoad 上发布通知。我有一个带有postNotification 方法的 BaseViewController,它获取一个枚举作为参数来识别屏幕。看起来是这样的

class BaseViewController {

    func postNotification(for screen: ScreenName) {
        NotificationCenter.default.post(name: notification,
                                        object: nil,
                                        userInfo: ["ScreenName": screen])
    }
}

class AViewController: BaseViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        postNotification(for: screenA)
    }
}

class BViewController: BaseViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        postNotification(for: screenB)
    }
}

假设我们以后需要添加另一个视图控制器,例如CViewController。我想强制CViewController 的开发者用屏幕枚举调用这个postNotification 方法。

在 Swift 上实现这一目标的最佳实践是什么?

编辑

感谢 Loren 的建议,我在我的基类上添加了一个协议

typealias BaseController = BaseViewController & BaseProtocol

protocol BaseProtocol {
    var screenName: ScreenName { get }
}

这会强制我所有的视图控制器遵守协议并初始化screenName,但现在我无法从我的BaseViewController 获取它。如果我可以从BaseViewController 获取子视图控制器的screenName 属性,我将消除对每个子视图调用postNotification 方法,并且只在BaseViewController 上调用它

【问题讨论】:

标签: ios swift oop


【解决方案1】:
class BaseViewController: UIViewController {

    var screenName: ScreenName!

    override func viewDidLoad() {
        super.viewDidLoad()
        if let screenName = self.screenName {
            self.postNotification(for: screenName)
        } else {
            fatalError("screenName must be instantiated")
        }
    }

    func postNotification(for screen: ScreenName) {
        NotificationCenter.default.post(name: notification,
                                        object: nil,
                                        userInfo: ["ScreenName": screen])
    }
}

class AViewController: BaseViewController {

    override func viewDidLoad() {
        self.screenName = screenA
        super.viewDidLoad()
    }
}

class BViewController: BaseViewController {

    override func viewDidLoad() {
        self.screenName = screenB
        super.viewDidLoad()
    }
}

试试这个,因为你正在使用继承,让 BaseViewController 继承 UIViewController 超类,然后创建一个 screenName 变量。在调用 super.viewDidLoad() 之前,在您的 childViewControllers 中实例化 screenName。您可以使用您提到的协议来强制实现变量,但对于一个变量来说似乎有点矫枉过正。

【讨论】:

  • 这并不能解决我最初的问题。开发人员可以添加 CViewController 而忘记在您的解决方案中设置 screenName。我想强制(给出编译时错误)开发人员更改 screenName。
  • BaseViewControllerviewDidLoad 中调用postNotification 时,安全地解开screenName 变量时添加了一个fatalError()。 super.viewDidLoad 将始终被调用
  • 感谢您更新您的答案,但这会导致运行时错误。我仍然相信应该有一个解决方案,给出编译时错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-22
  • 1970-01-01
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多