UIStoryboardSegue讲解.

什么是Segue

Storyboard上每一根用来界面跳转的线,都是一个UIStoryboardSegue对象(简称Segue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import <Foundation/Foundation.h>
#import <UIKit/UIKitDefines.h>

@class UIViewController;

NS_CLASS_AVAILABLE_IOS(5_0) @interface UIStoryboardSegue : NSObject

// Convenience constructor for returning a segue that performs a handler block in its -perform method.
+ (instancetype)segueWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination performHandler:(void (^)(void))performHandler NS_AVAILABLE_IOS(6_0);

- (instancetype)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination; // Designated initializer

@property (nonatomic, readonly) NSString *identifier;
@property (nonatomic, readonly) id sourceViewController;
@property (nonatomic, readonly) id destinationViewController;

- (void)perform;

@end

Segue的属性

每一个Segue对象,都有3个属性

  • @property (nonatomic, readonly) NSString *identifier; // 唯一标识

  • @property (nonatomic, readonly) id sourceViewController; // 来源控制器

  • @property (nonatomic, readonly) id destinationViewController; // 目标控制器

Segue的类型

根据Segue的执行(跳转)时刻,Segue可以分为2大类型

  • 自动型:点击某个控件后(比如按钮),自动执行Segue,自动完成界面跳转

设置方法:按住Control键,直接从控件(某个继承UIControl的控件)拖线到目标控制器.

一般来说,如果点击某个控件后,不需要做任何判断,一定要跳转到下一个界面,建议使用“自动型Segue

  • 手动型:需要通过写代码手动执行Segue,才能完成界面跳转

设置方法:

  1. 按住Control键,从来源控制器(当前控制器)拖线到目标控制器.
  2. 在Storyboard的Segue属性中设置唯一标识(一般来说命名建议为:”login2index”,既 当前控制器名称+2+目标控制器名称)
  3. 在适当的时候调用下面方法,来实现跳转.(适当的时候一般是设置控件时,或某些自动跳转)
1
2
- (void)performSegueWithIdentifier:(NSString *)identifier
sender:(id)sender

一般来说,如果点击某个控件后,需要做一些判断,也就是说:满足一定条件后才跳转到下一个界面,建议使用“手动型Segue”(比如用户登录,比如选择后等等)
 

performSegueWithIdentifier:sender: 方法完整执行过程

总得来说这个方法可以分为三个大的部分:

  • 1.根据identifierstoryboard中找到对应的线,新建UIStoryboardSegue对象
1
- (instancetype)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination; // Designated initializer

其实就是执行了这样一句,并且identifier就是在StoryboardSegue属性设置的标识. 来源就是连线的头部. 目标就是连线尾部.

  • 2.调用sourceViewController的下面方法,做一些跳转前的准备工作并且传入创建好的Segue对象
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;

    所谓跳转前的准备,因为可以拿到Segue(来源控制器,目标控制器),所以就可以在这里给下一个控制器传递数据.

注意的是:只能只能由来源控制器调用,来拿到目标控制器.

并且,这个sender是当初performSegueWithIdentifier:sender:中传入的sender.

另外需要注意的是:

  • 这个方法是系统默认调用,所以只需要实现即可.
  • 凡是performSegue都会来到这个方法.所以一般需要对Segue的标识进行判断.于是有了如下的两种固定格式:
1
2
3
4
5
6
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqual: @"login2index"]) {
// 需要执行的代码
}
}
1
2
3
4
5
6
7
8
#import "IndexTableViewController.h"

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.destinationViewController isKindOfClass:[IndexTableViewController class]]) {
// 执行代码
}
}

区别:第一种需要在设置标识的值,并且匹配. 第二种却是通过目标控制器判断

个人建议:使用第二种(既可以不在Storyboard输入标识,并且因为不涉及字符串,不容易出错.)

一个页面的跳转可能不止一个.并且为了后期的可维护性,建议加上标识判断.

  • 调用Segue对象的- (void)perform;方法开始执行界面跳转操作
    其实就是封装了Push方法:1.首先取得sourceViewController所在的UINavigationController. 2.然后调用UINavigationControllerpush方法将destinationViewController压入栈中,完成跳转.

但是如果类型是Modal,就是调用了SourceViewControllerpresentViewController方法将destinationViewController展示出来.

 

控制器之间的数据传递

根据segue我们可以吧控制器之间的数据传递分为两种情况:1.顺传 2.逆传

顺,逆关系由Segue决定

顺传:可以在prepareForSegue:sender:方法中根据segue参数取得目标控制器,直接给目标控制器传递数据模型.

逆传:只能让源控制器成为目标控制器的代理,然后通过代理方法传递数据.(采用解耦方法)

传递模型的好处是:假如一个数据需要顺传目标控制器,并且目标控制需要对数据进行了修改,这个时候修改的其实就是数据模型.(所以再次逆传的时候,可以不传数据).