Unwind Segue的工作原理和Modal presentation与Unwind segue的区别

转至http://www.cocoachina.com/ios/20141113/10212.html

Unwind Segue的工作原理大致如下:

● 当我们通过UI事件或手动调用performSegueWithIdentifier:sender:方法触发一个Unwind Segue以后,首先UIKit会发送canPerformUnwindSegueAction:fromViewController:withSender:消息到sourceViewController询问是否处理UnwindSegue的action,由于sourceViewController不能处理(Unwind到自身没有意义),会返回NO

● UIKit然后会寻找sourceViewController的父Controller。如果sourceController是嵌入Navigation View Controller的子Controller,那么父Controller就是其navigationController

● 之后UIKit会发送viewControllerForUnwindSegueAction:fromViewController:withSender:消息给navigationController,询问能否找到一个负责处理此action的子Controller

● 在navigationController的默认viewControllerForUnwindSegueAction:fromViewController:withSender:实现中,navigationController会向自己的navigation栈上的所有子Controller发送● canPerformUnwindSegueAction:fromViewController:withSender:消息。UIViewController类中,该方法的默认实现会查看unwinde segue action定义是否存在(即上面提到的特定签名的方法是否存在,这个方法的内部实现可以留空),若存在就返回YES。

● 如果navigationController的viewControllerForUnwindSegueAction:fromViewController:withSender:方法返回nil,则不会触发任何Unwind Segue

● 如果navgationController找到一个子类可以处理Unwind Segue的action,那么UIKit会发送segueForUnwindingToViewController:fromViewController:identifier:消息给navigationController,此方法将返回一个实际执行定制转场的segue实例

● 调用sourceViewController上的prepareForSegue:sender:方法

● 调用由viewControllerForUnwindSegueAction:fromViewController:withSender:方法返回的destinationViewController中的Segue action方法

● 调用Unwind Segue实例中的perform方法

从上面的我们可以知道,Unwind Segue的正常工作必须要有一个Container View Controller作为所有流程View Controller的父Controller来管理整个流程。在上面的原理说明中,这个父Controller是Navigation View Controller。如果我们要实现一个自己的定义的Container,就必须给自定义的View Controller类实现一些上面提到过的方法:

● canPerformUnwindSegueAction:fromViewController:withSender:

● viewControllerForUnwindSegueAction:fromViewController:withSender:

● segueForUnwindingToViewController:fromViewController:identifier:

2.Modal presentation与Unwind segue的区别

当我们使用UIViewController的presentViewController:animated:completion:方法以Modal presentation的方式来跳转场景的时候,情况与在Navigation View Controller有很大不同。首先,使用这种方式跳转场景的时候,跳转到的View Controller为Source View Controller的子Controller,而在Navigation View Controller中,所有的流程Controller基本上都是Navgation View Controller的子Controller,所以二者在View Controller的层次管理上有很多不同。因此实现Modal presentation风格的Segue的时候,动画的view不能搞错,必须对View Controller中的顶层View操作。一个参考实现如下(略掉动画效果代码,仅提供转场方法调用代码):

Segue部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- (UIView *)findTopMostViewForViewController:(UIViewController *)viewController
{
     UIView *theView = viewController.view;
     UIViewController *parentViewController = viewController.parentViewController;
     while  (parentViewController != nil)
     {
         theView = parentViewController.view;
         parentViewController = parentViewController.parentViewController;
     }
     return  theView;
}
 
- (void)perform
{
     UIViewController *source = self.sourceViewController;
     UIViewController *destination = self.destinationViewController;
 
     // Find the views that we will be animating. If the source or destination
     // view controller sits inside a container view controller, then the view
     // to animate will actually be that parent controller's view.
     UIView *sourceView = [self findTopMostViewForViewController:source];
     UIView *destinationView = [self findTopMostViewForViewController:destination];
 
     [source presentViewController:destination animated:NO completion:^{
         // completion code here
     }];
}

Unwind Segue部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- (UIView *)findTopMostViewForViewController:(UIViewController *)viewController
{
     UIView *theView = viewController.view;
     UIViewController *parentViewController = viewController.parentViewController;
     while  (parentViewController != nil)
     {
         theView = parentViewController.view;
         parentViewController = parentViewController.parentViewController;
     }
     return  theView;
}
 
- (void)perform
{
     UIViewController *source = self.sourceViewController;
     UIViewController *destination = self.destinationViewController;
 
     // Find the views that we will be animating. If the source or destination
     // view controller sits inside a container view controller, then the view
     // to animate will actually be that parent controller's view.
     UIView *sourceView = [self findTopMostViewForViewController:source];
     UIView *destinationView = [self findTopMostViewForViewController:destination];
 
     [source dismissViewControllerAnimated:NO completion:^{
         // completion code here
     }];
}

注意:Modal Presentation的Unwind Segue很难实现无Bug的任意跳转,因为UIViewController中,跟Container View Controller相关的方法的默认实现并不能很好的定位Container View Controller。而以正确的方式重写这些方法并不容易。所以如果有任意跳转的需求,我们可以尝试自己实现一个简单的Container View Controller。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值