如何使用segue和didSelectRowAtIndexPath进行界面跳转

#问题描述 在进行Master-Detail ViewController的开发时,经常遇到的问题就是:如何实现在MasterVC和DetailVC之间进行跳转。

##iOS5之前 在iOS5之前,由于没有storyboard和segue的概念。所以基本上都是通过NavigationVC进行push操作,把DetailVC加入都最顶端。例如当我们要实现点击Cell跳转到DetailVC时,我们经常会这样写:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
	DetailViewController *detailVC = [[DetailViewController alloc] init];
	[self.navigationController pushViewController:detailVC animated:YES]; //push操作
}

##iOS5之后 在iOS5之后,推出了storyboard和segue的概念,在IB的storyboard中,我们可以通过segue,把MasterVC和DetailVC之间的跳转关系关联起来。还是上面那个例子:“点击Cell跳转到DetailVC”。我们可以在Cell和DetailVC之间通过ctrl-drag创建一个segue,在Selection Segue下面选择push操作。最后需要在MasterVC中实现prepareForSegue方法。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if([segue.identifier isEqualToString:@"SegueIdentifier"]) {
        NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
        id dataSourceObject = [_objects objectAtIndex:indexPath.row];
        id detailViewController = segue.destinationViewController;
        detailViewController.dataSourceObject = dataSourceObject; //实现对象传递
    }
}

##单纯使用segue的问题 在现实开发中,我们经常会遇到这样的场景:点击MasterVC.cell时,在代码中通过if判断,选择性的跳转到不同的DetailVC中。然而,单纯使用prepareForSegue方法是无法做到的。

例如有两个DetailVC:DetailVC1,DetailVC2。当我们在IB中分别创建两个segue: MasterVC.cell---DetailVC1 和 MasterVC.cell---DetailVC2,IB却只允许我们创建一个segue!后面创建的segue会让之前创建的segue消失!原因是:在IB中对于同一个MasterVC.cell,IB只允许创建一个MasterVC.cell---DetailVC的Selection Segue(Accessory Action也是如此)。这导致我们无法在prepareForSegue方法中通过segue.identifier进行选择性判断。

##如何进行判断式的跳转 对于判断式的跳转,我们依然可以使用iOS5之前的做法:完全不使用storyboard和segue,而是直接在didSelectRowAtIndexPath方法中进行判断式跳转。但是当我们有很多VC时,VC间的跳转方式都隐藏在代码中,我们缺乏一个全局视图,清晰的阅读各个VC之间的跳转关系。因此现在不推荐使用此方式。

storyboard则提供了一个非常清晰、宏观的视图,使我们更加清楚的理解各个VC之间的跳转关系,***因此也更加推荐使用storyboard+segue的方式进行开发。***下面将介绍如果使用segue进行判断式的跳转。

##使用segue进行判断式的跳转 解决办法

  1. 不再创建MasterVC.cell---DetailVC的Selection Segue。改成创建MasterVC--DetailVC的Manual Segue。
  2. 实现didSelectRowAtIndexPath方法和prepareSegue方法。

也就是说,我们不再把segue跳转关系定义在cell与DetailVC之间,而是定义在两个Controller之间。这样,我们可以在一个MaterVC与多个DetailVC之间定义多个segue。此时创建的Segue是Manual Segue。Manual Segue只是把两个VC关联起来,但并不一定是通过selection的方式进行跳转。具体跳转方式由代码实现确定。

由于最终我们还是需要通过点击cell来触发跳转事件,因此需要实现didSelectRowAtIndexPath方法,并在方法中进行逻辑跳转判断。而每一个跳转后的具体内容则由prepareSegue方法实现。

//先执行
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    //获得被点击的cell
    UITableViewCell *selectedCell = [self.tableView cellForRowAtIndexPath:indexPath];
    //跳转逻辑判断
    if(indexPath.row%2==1) {
        [self performSegueWithIdentifier:ShowDetail1Segue sender:selectedCell];
    }
    else {
        [self performSegueWithIdentifier:ShowDetail2Segue sender:selectedCell];
    }
}

//后执行
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
    
    //跳转进行逻辑判断后,实现跳转后的具体内容,例如传递对象,初始化等等。
    if([segue.identifier isEqualToString:ShowDetail1Segue]) {
        DetailViewController1 *detailViewController1 = segue.destinationViewController;
        detailViewController1.text = [self.objects objectAtIndex:indexPath.row];
    }
    else if([segue.identifier isEqualToString:ShowDetail2Segue]) {
        DetailViewController2 *detailViewController2 = segue.destinationViewController;
        detailViewController2.text = [self.objects objectAtIndex:indexPath.row];
    }
}

##对于segue的理解 segue用于描述两个ViewController之间的关系。我们可以把segue分为两类:

  1. Manual Segue
  2. Selection Segue(Accessroy Segue也可以算是Selection Segue)

###Manual Segue Manual Segue仅仅描述了两个ViewController之间的关系。它并没有说明ViewController之间应该如何跳转。我们需要在代码中自己去实现跳转方式和跳转逻辑。例如上面的例子就是在点击cell时实现VC间的跳转,我们甚至可以在重力感应的触发下进行VC的跳转,一切都取决于我们如何在代码中触发跳转。

因此,在上面的例子中,你会发现didSelectRowAtIndexPath方法优先被调用,毕竟那是触发跳转的条件,跳转逻辑判断也在其中进行。然后通过performSegueWithIdentifier方法调用具体的跳转内容。

###Selection Segue Selection Segue不仅描述了两个ViewController之间存在关系,还把跳转触发条件限制在"点击cell"或"点击accessory"的时候触发跳转。同时IB还限制 Selection Segue不能关联多个DetailVC。

此时,如果在代码中同时实现了prepareSegue方法和didSelectRowAtIndexPath方法,程序会优先调用prepareSegue方法,相当于说是Selection Segued自带的点击触发事件优先级高于didSelectRowAtIndexPath方法的触发事件优先级。

即使我们在didSelectRowAtIndexPath方法中实现了判断式的跳转,程序还是会在跳转时崩溃。另外如果我们使用了storyboard创建VC,但没有使用segue跳转,而直接在didSelectRowAtIndexPath方法中进行跳转,此时程序也无法正常运行,且IB会提示警告,说明存在孤立的VC。

###隐含细节 Segue的常用跳转方式就是push。push操作其实是依赖于NavigationController来实现的。因此在使用segue的push跳转时,MasterVC必须包含在一个NavigationController中,否则在进行push跳转时程序会崩溃。

###小结 因此当我们需要进行判断式跳转时,请使用Manual Segue,并在代码中实现逻辑判断。如果我们仅需要实现点击cell/accessory时进行固定的跳转,则可以使用Selection Segue,并且仅需要实现prepareSegue方法,而不需要实现didSelectRowAtIndexPath方法。

##总结

  • 推荐使用Storyboard+Segue的方式创建和管理ViewController。不推荐使用iOS5之前的方式。
  • Manual Segue并没有自带点击事件,需要自己在代码中实现。适用于判断式跳转。
  • Selection Segue自带点击事件,适用于固定的跳转。

##Demo https://git.oschina.net/iSingular/ViewControllerTransition.git

#References

转载于:https://my.oschina.net/isingular/blog/615310

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值