在APP开发中,我们经常需要在不同的控制器之间进行数据传递,按照传递的方向,可分为顺传和逆传;按照是否通过第三者(如通过单例、或者文件等)传递数据,可以分为:直接传递和间接传递;一般的还把控制器之间的数据传递分为:属性传值、代理传值、Block传值、全局变量传值、文件传值(NSUserDefaults传值,或者通过其它数据持久化方式传值)、单例传值(UIApplication传值,通知传值,或自定义一个单例)
本篇博文主要讲解在storyboard中,控制器之间通过属性传递数据,后续会把其他传值方式写完
Storyboard中控制器的数据传递
一. 重点
接收数据的一方要有接收数据的属性,如果是逆传数据,要提前拿到接收数据的视图控制器
二. 知识点
Segue:Storyboard上每一根用来界面跳转的联线,都是一个UIStoryboardSegue对象(简称Segue)
Segue分为自动型和手动型,自动型一般用于不关心数据传递的,想直接通过按钮跳转到另外一个视图控制器的操作;手动型一般用于需要数据传递的操作,且Segue需要设置一个标识
identifier:只能通过storyboard设置,使用代码设置identifier没有意义,因为使用storyboard才有Segue
只有来源控制器才能执行performSegueWithIdentifier:sender:方法
三. 关于UIStoryboardSegue对象的底层执行
根据identifier去storyboard中找到对应的联线,新建UIStoryboardSegue对象,再设置UIStoryboardSegue对象的sourceViewController(来源控制器)和设置destinationViewController(目标控制器)
调用sourceViewController的performSegueWithIdentifier:sender:方法,做一些跳转前的准备工作并且传入创建好的Segue对象
调用Segue对象的performSegueWithIdentifier:sender:方法开始执行界面跳转操作,如果segue的style是push,取得sourceViewController所在的UINavigationController,调用UINavigationController的push方法将destinationViewController压入栈中,完成跳转;如果segue的style是modal,调用sourceViewController的presentViewController方法将destinationViewController展示出来
四. 具体步骤实现
1. 在storyboard中,拖入控制器
在storyboard中,把默认的视图控制器删除,并拖入一个导航控制器UINavigationController和两个视图控制器UIViewController,再把导航控制器默认的根控制器删除,最后对拖进来的两个视图控制器布局子控件
2. 设置导航控制器的根控制器
按住Ctrl键,从导航控制器拖线到视图控制器,并在选项框中选择“root view controller”
3. 设置导航控制器为程序启动默认加载的控制器
4. 拖线设置视图控制器之间的切换
按住Ctrl键,从视图控制器拖线到要跳转到的视图控制器,并在选项框中选择push
注意:是从视图控制器拖线到要跳转的视图控制器,而不是从按钮拖线到视图控制器
5. 设置storyboard中segue对象的标识符ID
6. 设置视图控制器的所属类
创建一个UIViewController的子类TwoViewController,然后把工程默认生成的ViewController和刚创建的TwoViewController设置为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