UIViewController中有这样两个属性,很多开发者以为presentingViewController就是把当前控制器模态(Modal)出来的控制器,presentedViewController就是当前控制器模态(Modal)出来的控制器.
presentingViewController
假设一个应用keyWindow的根视图控制器是A,然后A以Modal的方式推出带导航控制器B,B通过Push方式推出控制器C,C通过Push方式推出控制器D,D通过Push方式推出控制器E,那么此时E.presentingViewController指向那个对象?
回答这个问题之前,首先看一下presentingViewController是如何定义的.在开发文档中找到了这样的描述:
When you present a view controller modally (either explicitly or implicitly) using the
presentViewController:animated:completion:method, the view controller that was presented has this property set to the view controller that presented it. If the view controller was not presented modally, but one of its ancestors was, this property contains the view controller that presented the ancestor. If neither the current view controller or any of its ancestors were presented modally, the value in this property isnil.
意思就是无论开发者显性或者隐性的方式使用presentViewController:animated:completion:方式modal出一个视图控制器,这个被推出的控制器的presentingViewController属性就会被设置为推出它的控制器.如果当前控制器不是以Modal方式推出来的,但是其先祖(推出链中)某一个控制器被Modal出来的,则此属性包含显示祖先的视图控制器.如果当前控制器或者其先祖都不是被Modal出来的,这个属性的值就是nil.
根据文档的解释,问题中E控制器的推出链中,只有B是以Modal的方式推出的,所以B.presentingViewController指向了A,E.presentingViewController也指向了推出先祖(B)的控制器(A).所以E.presentingViewController指向了A.
现在思考另一个问题,如果视图控制器A被包含在UINavigationController中作为应用Window的跟视图控制器,此时E.presentingViewController是否还是指向A呢?
在ViewController Programming Guide部分有如下描述:
The view controller that calls the
presentViewController:animated:completion:method may not be the one that actually performs the modal presentation. The presentation style determines how that view controller is to be presented, including the characteristics required of the presenting view controller.
在The View Controller Hierachy中,找到了这样的描述:
When you present a view controller, UIKit looks for a view controller that provides a suitable context for the presentation. In many cases, UIKit chooses the nearest container view controller but it might also choose the window’s root view controller.
所以可以看到presentingViewController属性并不一定是直接调用presentViewController:animated:completion:的控制器,UIKit会去寻找一个能够为推出控制器提供合适环境的控制器.在很多场景中,系统会选择满足条件且距离最近的先祖,但是也有可能是应用window的根视图控制器.可以简单理解为,UIKit系统会在控制器的先祖链中查找一个适合的控制器用来展示当前控制器, 但是这个不是绝对的,UIKit很有可能会选择应用window的根视图控制器来进行Modal展示.
而且事实上默认设置下多数场景都会以应用window的跟视图控制器用作提供Modal操作的控制器.如果视图控制器A被包含在UINavigationController中作为window根视图控制器的时候,E.presentingViewController指向了其父视图控制器,也就是UINavigationController对象.
当然,如果你真的很通过presentingViewController获取到直接调用presentViewController:animated:completion:方法的控制器,还是有折中的办法的.
控制器还有一个属性definesPresentationContext,在开发文档中可以找到如下描述:
@property(nonatomic, assign) BOOL definesPresentationContext;When using the
UIModalPresentationCurrentContextorUIModalPresentationOverCurrentContextstyle to present a view controller, this property controls which existing view controller in your view controller hierarchy is actually covered by the new content. When a context-based presentation occurs, UIKit starts at the presenting view controller and walks up the view controller hierarchy. If it finds a view controller whose value for this property isYES, it asks that view controller to present the new view controller. If no view controller defines the presentation context, UIKit asks the window’s root view controller to handle the presentation.The default value for this property is
NO. Some system-provided view controllers, such asUINavigationController, change the default value toYES.
要表达的意思就是:在一般的控制器中,definesPresentationContext默认值是NO,但是在一些系统提供的控制器将这个默认值修改为YES.你可以将当前控制器的definesPresentationContext设置为YES,然后将目标控制器的modalPresentationStyle属性设置为UIModalPresentationCurrentContext或者UIModalPresentationOverCurrentContext,这样在Modal出来的新控制器中通过presentingViewController属性就可以获取到直接调用presentViewController:animated:completion:方法的控制器.
presentedViewController
这个属性就相对好理解一些:
When you present a view controller modally (either explicitly or implicitly) using the
presentViewController:animated:completion:method, the view controller that called the method has this property set to the view controller that it presented. If the current view controller did not present another view controller modally, the value in this property isnil.
所以只要当前控制器显性或者隐性调用presentViewController:animated:completion:方法,调用方法的控制器的presentedViewController就会被设置为被Modal出来的新控制器.
需要注意⚠️:该属性并不会持有Modal出来的控制器,所以只要Modal出来的控制器生命周期结束,该属性就会被置空.
深入探讨UIViewController中的presentingViewController和presentedViewController属性,解析它们在模态视图控制器呈现过程中的作用及UIKit如何选择合适的上下文进行视图展示。

4万+

被折叠的 条评论
为什么被折叠?



