我想为新应用实现MVP模式。因此除了专门涉及UI元素的视图之外,View不应该具有任何逻辑。因此,我想要从"口译员" (解释后面代码中的用户输入),然后从我的模型中请求数据并将其提供给" Presenter"。演示者拥有一个包含视图功能的协议。
问题是:从演示者调用updateUIData()
会产生
致命错误:在解包可选值时意外发现nil
从同一位置的View中调用函数工作正常。
我怀疑错误来自演示者初始化中特定MainViewController的初始化,但如果我的猜测正确,我不知道如何解决这个问题。
这是我的(相关)代码:
MainViewController:
class MainViewController: UIViewController {
lazy var interpreter = Interpreter() // lazy needed b/c Interpreter holds Presenter which holds MainViewController
@IBOutlet var dateLabel: UILabel!
@IBOutlet var totalTimeLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// updateUIData()
requestData()
}
func requestData() {
interpreter.requestData()
}
}
extension MainViewController: MainViewSetters {
func updateUIData() {
dateLabel.text = "Data"
totalTimeLabel.text = "loaded"
}
}
MainViewSetters(协议):
protocol MainViewSetters {
func updateUIData()
}
解释器:
class Interpreter {
let presenter = Presenter()
func requestData() {
// normally: get data from model and pass it to presenter
presenter.presentData()
}
}
主讲人:
class Presenter {
let mainView: MainViewSetters
init(withMainViewController mainVC: MainViewSetters = MainViewController()) {
mainView = mainVC
}
func presentData() {
mainView.updateUIData()
}
}
答案 0 :(得分:1)
您的问题是,您没有将MainViewController
的引用传递给Presenter
的实例。
此代码:
lazy var interpreter = Interpreter()
应该更像这样:(这里需要输入类型因为懒惰,编译器无法正确推断)
lazy var interpreter: Interpreter = Interpreter(for: self)
然后你必须在Interpreter
中创建一个特殊的初始化器,它将viewController实例传递给它的presenter
属性:
class Interpreter {
let presenter: Presenter
init(for viewController: MainViewSetters) {
presenter = Presenter(withMainViewController: viewController)
}
func requestData() {
// normally: get data from model and pass it to presenter
presenter.presentData()
}
}
我还强烈建议您将默认值移至Presenter
的{{1}}方法,您不太可能希望将init
的随机实例指定为{{1}任何MainViewController
对象。
最后,请注意,此代码正在创建保留周期,您的mainView
实例和Presenter
实例都不会被释放。这是因为MainViewController
类拥有对Presenter
实例及其属性Presenter
的强引用。要解决此问题,您必须将MainViewController
标记为弱,并将其设为可选。
请参阅下面的固定实施:
mainView
要使mainView
在class Presenter {
weak var mainView: MainViewSetters?
init(withMainViewController mainVC: MainViewSetters) {
mainView = mainVC
}
func presentData() {
mainView?.updateUIData()
}
}
类型的属性上可接受(不是真实类型而只是协议),您必须指定其仅应用于类的协议:
weak
答案 1 :(得分:1)
您正在初始化传递默认MainViewController()的解释器。 从以下代码更改该代码:
lazy var interpreter = Interpreter()
到
lazy var interpreter = Interpreter(withMainViewController: self)