哪个对象负责对UIViewController
旋转方法调用进行双重调整,即:
shouldAutorotateToInterfaceOrientation:
willRotateToInterfaceOrientation:duration:
willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
didRotateFromInterfaceOrientation:
我想它是UIApplication
(但可能是AppDelegate或UIWindow)。
接下来的问题是,对象如何知道与UIViewController
进行对话?
它如何知道哪个UIViewController
将其视图作为窗口的子视图?
是否有可以发送的消息或您可以设置的属性(某个对象)为应用设置“有效”UIViewController
?
答案 0 :(得分:13)
似乎UIApplication
正在向活动视图控制器发送消息。
但是,您的View Controller实例如何获取这些消息?
邮件将转发到第一个视图控制器,该视图的视图已添加到UIWindow
实例。
这归结为3种基本情景:
视图为的ViewController
直接添加到UIWindow
实例(单一视图应用程序)
a中的导航控制器 基于导航的应用程序,然后是 导航控制器转发 消息到活动视图视图 控制器。
标签栏中的标签栏控制器 基于应用程序,然后是标签栏 控制器将消息转发给 活动视图视图控制器(或 主动导航控制器)。
您将遇到的问题是,如果您构建具有多个视图的应用程序,但不要使用导航控制器或Tab Bar控制器。如果您手动交换视图进出UIWindow
实例,则不会可靠地接收这些消息。
这类似于这样的帖子:
iPhone viewWillAppear not firing
只需将Apple的约定用于多个视图,您就可以了。希望这能节省一两个小时
答案 1 :(得分:4)
这就是你永远不会担心的魔法。只需将控制器的根视图添加到窗口中 - 或者让标签栏或导航控制器为您执行此操作 - 它将收到这些消息。
(但是如果你使用调试器,你可能得出相同的结论:有一些内部表将每个控制器的视图映射回控制器,并根据该链接调度消息。)< / p>
更新:这是我在2009年第一次写这个答案时真正的私人魔法,但后来对iOS的改变使得它背后的API公之于众。现在可以通过UIWindow.rootViewController
属性访问根视图控制器,并使用UIViewController.childViewControllers
属性形成后代视图控制器树。
父视图控制器负责通知其子项方向更改。 (我不确定如何通知根视图控制器,但您可以设置断点并自行查找。)-shouldAutomaticallyForwardRotationMethods
方法决定UIViewController是否会为您执行此操作。如果它返回NO
,您将对-willRotateToInterfaceOrientation:duration:
,-willAnimateRotationToInterfaceOrientation:duration:
和-didRotateFromInterfaceOrientation:
方法负责。
答案 2 :(得分:4)
它如何知道哪个UIViewController将其视图作为窗口的子视图?
UIViewController类在视图及其视图控制器之间维护静态映射。在CocoaTouch内的几个关键位置查询此映射。特别是,[UIView nextResponder]查询它并返回控制器(如果找到)。
我猜UIWindow使用其根视图执行相同的查找,以了解将旋转事件转发到哪个控制器。下次我会在反汇编中查看一下这个。 (我花了一些时间对CocoaTouch进行逆向工程,以了解其中的工作原理。)
答案 3 :(得分:1)
我有类似的问题。
我有一个横向工作的游戏(左右两个景观)。
为了管理多视图应用程序,我使用了一个根UIviewController,即一个虚拟的UIView控制器,其UIview不执行任何操作。然后我将其他所有UIview作为子视图添加到其中。
启动应用程序时,模拟器会快速旋转到纵向,我的每个视图的框架属性看起来都像(0,-80,320,480)。这导致视图被右侧的160 X 320矩形剪切。
我注意到每个子视图的 - shouldAutorotateToInterfaceOrientation:方法只被调用一次,并且当它被添加到根视图时会发生这种情况。稍后,在旋转设备时,只有根视图才会调用它的方法。
不出所料,任何一个 - willAnimate *方法调用都只发送到根视图,因此,在子视图中定义任何这些方法都是没有意义的。
每次将方向更改为 - shouldAutorotateToInterfaceOrientation:方法接受的方向时,都会调用这些方法。所以我想我可以从那里开始我的子视图的框架属性。
为此,我在rootViewController类中定义了以下方法:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
subview1_ViewController.view.frame = CGRectMake(0,0,480,320);
subview2_ViewController.view.frame = CGRectMake(0,0,480,320);
...
}
我不明白为什么frame属性没有更新,但我知道这个解决方法有效。
希望这会有所帮助......