在我看来,这些情况都是平行的:
-
我的视图控制器提供了另一个视图控制器全屏,现在已经被驳回
-
我的视图控制器提供了另一个不是全屏的视图控制器,它现在已经被驳回
-
我的视图控制器显示了一个弹出窗口,现在已经被驳回
-
我的视图控制器推了另一个视图控制器,现在已经弹出
在任何情况下,我的视图控制器都不再是"最前面"的视图控制器,然后又变成了"最前面的"。我觉得奇怪的是,iOS没有一个"成为最前沿"的事件发送到我的视图控制器,涵盖了所有这些情况。
我认为我可以单独覆盖中的每一个案例,我认为这些都是我需要覆盖的所有案例,但结果代码令人困惑和分散:
-
viewDidAppear
检测到按下的视图控制器弹出和全屏显示的视图控制器消失 -
popover委托消息检测popover 的取消
-
不确定是什么检测到非全屏显示的视图控制器被取消
人们如何连贯优雅地处理这一问题?
这些情况的共同点不是原始视图控制器的出现,而是呈现/推送的视图控制器的消失。因此,一个简单明了的解决方案似乎是协议和委托体系结构。声明一对协议,如下所示:
protocol Home : class {
func comingHome()
}
protocol Away : class {
var home : Home? {get set}
}
extension Away where Self : UIViewController {
func notifyComingHome() {
if self.isBeingDismissed || self.isMovingFromParent {
self.home?.comingHome()
}
}
}
主视图控制器必须采用home,并且在呈现或推送时必须将每个视图控制器的
home
设置为self
。呈现或推送的视图控制器必须采用Away,并且必须实现如下
viewWillDisappear
:override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) self.notifyComingHome() }
这适用于问题中列出的四种情况。遗憾的是,Cocoa Touch并没有自动为你做到这一点。
EDIT由于iOS 13强制我们使用非全屏显示的视图控制器,这种方法在我的应用程序中变得更加重要。此外,我还将UIAlertController细分为子类,使其符合Away。
一种解决方案可以像MVVM-C风格的体系结构一样采用Coordinator方法。在VC中,您从不直接更改视图层次结构,而是总是调用Coordinator来为您更改。coordinator.showDetails(…)
此外,您在VC中定义了一个viewDidBecomeForemost
方法,协调器可以在返回到VC时调用该方法