控制器之间的数据传递——storyboard中控制器的数据传递

时间:2021-02-02 20:40:01

在APP开发中,我们经常需要在不同的控制器之间进行数据传递,按照传递的方向,可分为顺传和逆传;按照是否通过第三者(如通过单例、或者文件等)传递数据,可以分为:直接传递和间接传递;一般的还把控制器之间的数据传递分为:属性传值、代理传值、Block传值、全局变量传值、文件传值(NSUserDefaults传值,或者通过其它数据持久化方式传值)、单例传值(UIApplication传值,通知传值,或自定义一个单例)
本篇博文主要讲解在storyboard中,控制器之间通过属性传递数据,后续会把其他传值方式写完

Storyboard中控制器的数据传递

一. 重点

接收数据的一方要有接收数据的属性,如果是逆传数据,要提前拿到接收数据的视图控制器

二. 知识点

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

  2. Segue分为自动型和手动型,自动型一般用于不关心数据传递的,想直接通过按钮跳转到另外一个视图控制器的操作;手动型一般用于需要数据传递的操作,且Segue需要设置一个标识

  3. identifier:只能通过storyboard设置,使用代码设置identifier没有意义,因为使用storyboard才有Segue

  4. 只有来源控制器才能执行performSegueWithIdentifier:sender:方法

三. 关于UIStoryboardSegue对象的底层执行

  1. 根据identifier去storyboard中找到对应的联线,新建UIStoryboardSegue对象,再设置UIStoryboardSegue对象的sourceViewController(来源控制器)和设置destinationViewController(目标控制器)

  2. 调用sourceViewController的performSegueWithIdentifier:sender:方法,做一些跳转前的准备工作并且传入创建好的Segue对象

  3. 调用Segue对象的performSegueWithIdentifier:sender:方法开始执行界面跳转操作,如果segue的style是push,取得sourceViewController所在的UINavigationController,调用UINavigationController的push方法将destinationViewController压入栈中,完成跳转;如果segue的style是modal,调用sourceViewController的presentViewController方法将destinationViewController展示出来

四. 具体步骤实现

1. 在storyboard中,拖入控制器

在storyboard中,把默认的视图控制器删除,并拖入一个导航控制器UINavigationController和两个视图控制器UIViewController,再把导航控制器默认的根控制器删除,最后对拖进来的两个视图控制器布局子控件

控制器之间的数据传递——storyboard中控制器的数据传递

2. 设置导航控制器的根控制器

按住Ctrl键,从导航控制器拖线到视图控制器,并在选项框中选择“root view controller”

控制器之间的数据传递——storyboard中控制器的数据传递

3. 设置导航控制器为程序启动默认加载的控制器

控制器之间的数据传递——storyboard中控制器的数据传递

4. 拖线设置视图控制器之间的切换

按住Ctrl键,从视图控制器拖线到要跳转到的视图控制器,并在选项框中选择push
注意:是从视图控制器拖线到要跳转的视图控制器,而不是从按钮拖线到视图控制器

控制器之间的数据传递——storyboard中控制器的数据传递

控制器之间的数据传递——storyboard中控制器的数据传递

5. 设置storyboard中segue对象的标识符ID

控制器之间的数据传递——storyboard中控制器的数据传递

6. 设置视图控制器的所属类

创建一个UIViewController的子类TwoViewController,然后把工程默认生成的ViewController和刚创建的TwoViewController设置为storyboard里拖入的两个视图控制器的所属类

控制器之间的数据传递——storyboard中控制器的数据传递


控制器之间的数据传递——storyboard中控制器的数据传递

7. 编写数据传递相关代码

(1). ViewController类

---------- ViewController.h文件

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

// 接收界面2的数据
@property (nonatomic,strong) NSString *oneStr;

@end

---------- ViewController.m文件

#import "ViewController.h"
#import "TwoViewController.h"

@interface ViewController ()
// 显示界面2传来的数据
@property (weak, nonatomic) IBOutlet UILabel *oneLabel;
// 收集数据
@property (weak, nonatomic) IBOutlet UITextField *oneTextField;

@end

@implementation ViewController

// 在视图即将显示时,把接受到的值赋值给子控件
// 注意:不能在逆序传值的时候直接给子控制赋值,因为传值的时候要接收值的视图还没有加载,不能接收值
- (void)viewWillAppear:(BOOL)animated {

// 把届面2传回的值给oneLabel
self.oneLabel.text = self.oneStr;
}

// 通过UIStoryboardSegue对象切换视图,会调用此方法
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// 获取目的控制器
TwoViewController *vc= segue.destinationViewController;

// 给目的控制器赋值,即把界面1的文本框的数据给界面2
vc.nameStr = self.oneTextField.text;

// 把界面1的控制器给届面2,用于数据的逆序传递
vc.oneVC = self;

}

// 跳转方法
- (IBAction)jump:(id)sender {

// 设置Segue对象的标识符,注意要与storyboard中所设置的标识符相同
NSString *segueIdentifie = @"oneToTwo";

// 会通过标识符加载storyboard里面的Segue对象
[self performSegueWithIdentifier:segueIdentifie sender:nil];

}

@end

(2). TwoViewController类

---------- TwoViewController.h文件

#import <UIKit/UIKit.h>
#import "ViewController.h"

@interface TwoViewController : UIViewController
// 接收界面1的数据
@property (nonatomic,strong) NSString *nameStr;
// 保存界面1的控制器
@property (nonatomic,strong) ViewController *oneVC;

@end

---------- TwoViewController.m文件

#import "TwoViewController.h"
#import "ViewController.h"

@interface TwoViewController ()
// 显示界面一传来的数据
@property (weak, nonatomic) IBOutlet UILabel *twoLabel;
// 收集数据
@property (weak, nonatomic) IBOutlet UITextField *twoTextfield;

@end

@implementation TwoViewController

// 跳转方法
- (IBAction)twoToOne:(id)sender {

// 1.把数据传到界面1
self.oneVC.oneStr = self.twoTextfield.text;

// 2.跳转到界面1
[self.navigationController popViewControllerAnimated:YES];

}

- (void)viewDidLoad {
[super viewDidLoad];

// 把界面1传来的数据给twoLabel
self.twoLabel.text = _nameStr;

}

@end