Bootstrap

IOS界面传值-OC

1、页面跳转

由 ViewController 页面跳转至 NextViewController 页面

(1)ViewController

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

@interface ViewController : UIViewController


@end

  • ViewController.m
#import "ViewController.h"
#import "NextViewController.h"

@interface ViewController ()



@property (nonatomic, strong) UILabel *label;
@property (nonatomic, strong) UIButton *button;



@end


@implementation ViewController


//懒加载 UILabel
-(UILabel *) label{
    if (_label == nil) {
        _label = [[UILabel alloc]initWithFrame:CGRectMake(100, 100, 200, 50)];
        _label.backgroundColor = [UIColor blackColor];
        _label.textColor = [UIColor whiteColor];
        _label.font = [UIFont systemFontOfSize:20];
    }
    return _label;
}



//懒加载 UIButton
-(UIButton *) button{
    if (_button == nil) {
        _button = [[UIButton alloc]initWithFrame:CGRectMake(100, 200, 200, 50)];
        _button.backgroundColor = [UIColor redColor];
        //setTitle:forState: 是 UIButton 的方法,允许你为按钮的不同状态设置不同的标题
        //为按钮在 普通状态 (UIControlStateNormal) 下设置标题为 "跳转至下个页面"
        [_button setTitle:@"跳转至下个页面" forState:UIControlStateNormal];
        //setTitleColor:forState: 是 UIButton 的方法,允许你为不同状态下的按钮标题设置不同的颜色
        //为按钮在 触摸抬起 (UIControlEventTouchUpInside) 事件时,设置标题颜色为白色 ([UIColor whiteColor])
        [_button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        
        //点击事件
        //addTarget:action:forControlEvents:
        //target: 触发事件时的目标对象。通常是 self,即当前类的实例
        //action: 事件触发时调用的方法的 选择器,通过 @selector 来指定方法
        //forControlEvents: 指定触发事件的类型
        
        //UIControlEventTouchUpInside 按钮的 触摸抬起 事件
        [_button addTarget:self action:@selector(zlzButtonClick) forControlEvents:UIControlEventTouchUpInside];
        
        
    }
    return _button;
}


//按钮点击事件
-(void)zlzButtonClick{
    NextViewController *nextVC = [[NextViewController alloc]init];
    //NextViewController 需要全屏展示
    nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
    
    
    //presentViewController:animated:completion:
    //viewControllerToPresent: 需要展示的视图控制器
    //animated: 是否使用动画过渡
    //completion: 动画完成后的回调,可以是 nil
    [self presentViewController:nextVC animated:YES completion:nil];
}




/**
 
 •    viewDidLoad:视图加载后,初始化视图。
 •    viewWillAppear::视图即将显示,准备更新 UI。
 •    viewDidAppear::视图已显示,启动交互或动画。
 •    viewWillDisappear::视图即将隐藏,保存数据。
 •    viewDidDisappear::视图已隐藏,释放资源或暂停任务。
 **/




//视图加载
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor greenColor];
    NSLog(@"First viewDidLoad");
    //添加控件至根View
    [self.view addSubview:self.label];
    [self.view addSubview:self.button];
}




-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    NSLog(@"------First viewWillAppear");
}



- (void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];
    NSLog(@"------First viewWillLayoutSubviews");
}

- (void)viewDidLayoutSubviews{
    [super viewDidLayoutSubviews];
    NSLog(@"------First viewDidLayoutSubviews");
}



- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    NSLog(@"------First viewDidAppear");
}

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    NSLog(@"------First viewWillDisappear");
}

- (void)viewDidDisappear:(BOOL)animated{
    NSLog(@"------First viewDidDisappear");
}




@end



(2)NextViewController

  • NextViewController.h
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface NextViewController : UIViewController


@end

NS_ASSUME_NONNULL_END
  • NextViewController.m

#import "NextViewController.h"

@interface NextViewController ()


@property (strong, nonatomic) UITextField *textFiled;
@property (strong, nonatomic) UIButton *button;


@end

@implementation NextViewController


-(UITextField *)textFiled{
    if (_textFiled == nil) {
        _textFiled = [[UITextField alloc]initWithFrame:CGRectMake(100, 300, 200, 50)];
        _textFiled.textColor = [UIColor blackColor];
        _textFiled.borderStyle = UITextBorderStyleLine;
    }
    
    return _textFiled;
}



-(UIButton *) button{
    if (_button == nil) {
        _button = [[UIButton alloc]initWithFrame:CGRectMake(100, 400, 200, 50)];
        _button.backgroundColor = [UIColor redColor];
        [_button setTitle:@"返回上一个页面" forState:UIControlStateNormal];
        [_button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        
        //点击事件
        [_button addTarget:self action:@selector(zlzBackClick) forControlEvents:UIControlEventTouchUpInside];
    }
    
    return _button;
}




-(void)zlzBackClick{
    
    // dismissViewControllerAnimated:animated:completion:
    //用来 关闭当前视图控制器 的方法,通常用于关闭通过 presentViewController:animated:completion: 模态展示的视图控制器
    //completion:nil:表示关闭完成后执行的回调
    [self dismissViewControllerAnimated:YES completion:nil];
}





- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"------Second viewDidLoad");
    self.view.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:self.textFiled];
    [self.view addSubview:self.button];
}


- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    NSLog(@"------Second viewWillAppear");
}



- (void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];
    NSLog(@"------Second viewWillLayoutSubviews");
}

- (void)viewDidLayoutSubviews{
    [super viewDidLayoutSubviews];
    NSLog(@"------Second viewDidLayoutSubviews");
}




- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    NSLog(@"------Second viewDidAppear");
}

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    NSLog(@"------Second viewWillDisappear");
}

- (void)viewDidDisappear:(BOOL)animated{
    NSLog(@"------Second viewDidDisappear");
}




@end

2、界面传值

2.1、属性传值

  • 在 NextViewController.h 添加属性 str
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface NextViewController : UIViewController



//属性传值
@property (nonatomic, strong) NSString *str;



@end

NS_ASSUME_NONNULL_END

  • 在 ViewController.m 的跳转点击事件中 为NextViewController中的属性str 赋值
//按钮点击事件
-(void)zlzButtonClick{
    NextViewController *nextVC = [[NextViewController alloc]init];
    //NextViewController 需要全屏展示
    nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
    
    
    //属性传值---传递
    nextVC.str = @"属性传值";
    

    //presentViewController:animated:completion:
    //viewControllerToPresent: 需要展示的视图控制器
    //animated: 是否使用动画过渡
    //completion: 动画完成后的回调,可以是 nil
    [self presentViewController:nextVC animated:YES completion:nil];
}

  • 在 NextViewController.m 中 textFiled 懒加载时赋值
-(UITextField *)textFiled{
    if (_textFiled == nil) {
        _textFiled = [[UITextField alloc]initWithFrame:CGRectMake(100, 300, 200, 50)];
        _textFiled.textColor = [UIColor blackColor];
        _textFiled.borderStyle = UITextBorderStyleLine;
        
        //属性传值---接收并显示
        _textFiled.text = self.str;
    }
    
    return _textFiled;
}

  • 效果

2.2、单例传值

(1)创建单例

  • DefaultInstance.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface DefaultInstance : NSObject


+(instancetype)getInstance;

@property (nonatomic, strong) NSString *instanceStr;

@end

NS_ASSUME_NONNULL_END

  • DefaultInstance.m

#import "DefaultInstance.h"

@implementation DefaultInstance


//类方法---创建单例对象
+(instancetype)getInstance{
    //首次创建会 将 sharedVC 赋值为 nil,然后创建一个对象
    //非首次都会直接返回上次的值
    static DefaultInstance *instance = nil;
    if (instance == nil) {
        instance = [[DefaultInstance alloc]init];
    }
    return instance;
}


@end

(2)正向传值

  • 在 ViewController.m 的跳转点击事件,为单例的属性值赋值
//按钮点击事件
-(void)zlzButtonClick{
    NextViewController *nextVC = [[NextViewController alloc]init];
    //NextViewController 需要全屏展示
    nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
    
    
    //单例传值---正向传递
    [DefaultInstance getInstance].instanceStr = @"单例传值";
    
    
    //presentViewController:animated:completion:
    //viewControllerToPresent: 需要展示的视图控制器
    //animated: 是否使用动画过渡
    //completion: 动画完成后的回调,可以是 nil
    [self presentViewController:nextVC animated:YES completion:nil];
}

  • 在 NextViewController.m 的 textFiled懒加载时赋值
-(UITextField *)textFiled{
    if (_textFiled == nil) {
        _textFiled = [[UITextField alloc]initWithFrame:CGRectMake(100, 300, 200, 50)];
        _textFiled.textColor = [UIColor blackColor];
        _textFiled.borderStyle = UITextBorderStyleLine;

        //单例传值---接收并显示
        _textFiled.text = [DefaultInstance getInstance].instanceStr;
    }
    
    return _textFiled;
}

  • 效果

(3)反向传值

  • 在 NextViewController.m 的返回点击事件中,为单例中的属性赋值
-(void)zlzBackClick{
    
    
    //单例传值---反向传递
    NSLog(@"单例传值---反向传递: %@",self.textFiled.text);
    [DefaultInstance getInstance].instanceStr = self.textFiled.text;
    
    // dismissViewControllerAnimated:animated:completion:
    //用来 关闭当前视图控制器 的方法,通常用于关闭通过 presentViewController:animated:completion: 模态展示的视图控制器
    //completion:nil:表示关闭完成后执行的回调
    [self dismissViewControllerAnimated:YES completion:nil];
}

  • 在 ViewController.m 的 viewWillAppear() 方法中,获取单例属性值并展示
-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    NSLog(@"------First viewWillAppear");
    //单例传值---反向接收并展示
    NSLog(@"单例传值---反向接收并展示:%@", [DefaultInstance getInstance].instanceStr);
    self.label.text = [DefaultInstance getInstance].instanceStr;
}

  • 效果

2.3、NSUserDefaults传值

NSUserDefaults传值与单例传值类似,区别是单例传值是在内存中创建单例,而NSUserDefaults 则是在磁盘文件中的。

(1)正向传值

  • 在 ViewController.m 中的跳转点击事件中将值写入文件
//按钮点击事件
-(void)zlzButtonClick{
    NextViewController *nextVC = [[NextViewController alloc]init];
    //NextViewController 需要全屏展示
    nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
    
    
    //NSUserDefaults-正向传值(存入磁盘文件)
    [[NSUserDefaults standardUserDefaults] setObject:@"NSUserDefaults传值" forKey:@"zlzKey"];
    //写入
    [[NSUserDefaults standardUserDefaults] synchronize];
    
    
    //presentViewController:animated:completion:
    //viewControllerToPresent: 需要展示的视图控制器
    //animated: 是否使用动画过渡
    //completion: 动画完成后的回调,可以是 nil
    [self presentViewController:nextVC animated:YES completion:nil];
}

  • 在 NextViewController.m 的 textFiled 懒加载时赋值
-(UITextField *)textFiled{
    if (_textFiled == nil) {
        _textFiled = [[UITextField alloc]initWithFrame:CGRectMake(100, 300, 200, 50)];
        _textFiled.textColor = [UIColor blackColor];
        _textFiled.borderStyle = UITextBorderStyleLine;
        

        //NSUserDefaults传值---接受并显示(从磁盘文件中读取)
        _textFiled.text = [[NSUserDefaults standardUserDefaults] objectForKey:@"zlzKey"];
        
    }
    
    return _textFiled;
}

  • 效果

(2)反向传值

  • 在 NextViewController.m 中的返回点击事件中将值写入文件
-(void)zlzBackClick{
    
    //NSUserDefaults传值---反向传递
    NSLog(@"NSUserDefaults传值---反向传递:%@", self.textFiled.text);
    [[NSUserDefaults standardUserDefaults] setObject:self.textFiled.text forKey:@"zlzBackKey"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    
    
    // dismissViewControllerAnimated:animated:completion:
    //用来 关闭当前视图控制器 的方法,通常用于关闭通过 presentViewController:animated:completion: 模态展示的视图控制器
    //completion:nil:表示关闭完成后执行的回调
    [self dismissViewControllerAnimated:YES completion:nil];
}

  • 在 ViewController.m 中的 viewWillAppear() 方法中获取文件中的值
-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    NSLog(@"------First viewWillAppear");

    //NSUserDefaults传值---反向接收并展示
    NSLog(@"NSUserDefaults---反向接收并展示:%@", [[NSUserDefaults standardUserDefaults] objectForKey:@"zlzBackKey"]);
    self.label.text = [[NSUserDefaults standardUserDefaults] objectForKey:@"zlzBackKey"];
}

  • 效果

2.4、代理传值

  • 代理传值主要应用于反向传值,即本示例中 NextViewController -> ViewController 传值
  • 委托方:NextViewController
  • 代理方:ViewController

(1)委托方 NextViewController 定义协议

  • 在 NextViewController.h 中创建协议

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN



//委托方定义协议
@protocol zlzPassValueDelegate <NSObject>

//协议定义一个方法
-(void)passValue:(NSString*)value;

@end



@interface NextViewController : UIViewController



//属性传值
@property (nonatomic, strong) NSString *str;



//定义一个持有协议的id指针
//weak是为了防止指针循环引用
@property (weak)id<zlzPassValueDelegate> zlzDelegate;



@end

NS_ASSUME_NONNULL_END

  • 在 NextViewController.m 中调用协议方法
-(void)zlzBackClick{
    
    //代理传值---反向传递
    [self.zlzDelegate passValue:self.textFiled.text];
    
    
    
    // dismissViewControllerAnimated:animated:completion:
    //用来 关闭当前视图控制器 的方法,通常用于关闭通过 presentViewController:animated:completion: 模态展示的视图控制器
    //completion:nil:表示关闭完成后执行的回调
    [self dismissViewControllerAnimated:YES completion:nil];
}

(2)代理方 ViewController 实现协议方法

  • 在 ViewController.m 中实现协议方法
#import "ViewController.h"
#import "NextViewController.h"

@interface ViewController ()<zlzPassValueDelegate>   //遵守协议


@property (nonatomic, strong) UILabel *label;
@property (nonatomic, strong) UIButton *button;



@end

@implementation ViewController


//...省略部分代码


//代理传值---实现协议方法
-(void)passValue:(NSString *)value{
    self.label.text = value;
}


@end

(3)绑定代理关系

  • 在 ViewController.m 的跳转点击事件中,设置 NextViewController 的代理是自己

//按钮点击事件
-(void)zlzButtonClick{
    NextViewController *nextVC = [[NextViewController alloc]init];
    //NextViewController 需要全屏展示
    nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
    
    
    
    //代理传值---设置代理关系
    nextVC.zlzDelegate = self;
    
    
    //presentViewController:animated:completion:
    //viewControllerToPresent: 需要展示的视图控制器
    //animated: 是否使用动画过渡
    //completion: 动画完成后的回调,可以是 nil
    [self presentViewController:nextVC animated:YES completion:nil];
}

2.5、block传值

block传值与代理传值有点类似,也是主要应用于反向传值,但是使用起来比代理传值要简单。

  • 在 NextViewController.h 中定义 block
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN


@interface NextViewController : UIViewController



//属性传值
@property (nonatomic, strong) NSString *str;


// 定义一个 block 进行页面反向传值
//copy属性是为了防止 block 循环引用
//block就是一个属性
//^就是block的标志
@property (copy) void (^zlzBlock)(NSString*);


@end

NS_ASSUME_NONNULL_END
  • 在 NextViewController.m 中的返回点击事件中调用 block 方法
-(void)zlzBackClick{
    
    //block传值---反向传递
    self.zlzBlock(self.textFiled.text);
    
    
    
    // dismissViewControllerAnimated:animated:completion:
    //用来 关闭当前视图控制器 的方法,通常用于关闭通过 presentViewController:animated:completion: 模态展示的视图控制器
    //completion:nil:表示关闭完成后执行的回调
    [self dismissViewControllerAnimated:YES completion:nil];
}

  • 在 ViewController.m 中的跳转点击事件中实现 属性 block
-(void)zlzButtonClick{
    NextViewController *nextVC = [[NextViewController alloc]init];
    //NextViewController 需要全屏展示
    nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
        
    
    
    //block传值---实现block-接收来自页面2的值
    nextVC.zlzBlock = ^(NSString *value){
        self.label.text = value;
    };
    
    
    
    //presentViewController:animated:completion:
    //viewControllerToPresent: 需要展示的视图控制器
    //animated: 是否使用动画过渡
    //completion: 动画完成后的回调,可以是 nil
    [self presentViewController:nextVC animated:YES completion:nil];
}

2.6、通知传值

通知传值更灵活,主要用于跨页面跳转时。

类似于Android中的广播。

(1)接收方 ViewController

  • 在 ViewController.m 的跳转点击事件中,设置通知监听
-(void)zlzButtonClick{
    NextViewController *nextVC = [[NextViewController alloc]init];
    //NextViewController 需要全屏展示
    nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
    

    
    //通知传值---添加监听,等待页面2的传值
    //addObserver:self 添加监听者为自己
    //通知的名称zlzNotify
    //object:nil 表示所有的发送者,只要是名为zlzNotify通知的都监听接收
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealWithNotify:) name:@"zlzNotify" object:nil];
    
    
    
    
    
    //presentViewController:animated:completion:
    //viewControllerToPresent: 需要展示的视图控制器
    //animated: 是否使用动画过渡
    //completion: 动画完成后的回调,可以是 nil
    [self presentViewController:nextVC animated:YES completion:nil];
}



//接收到通知后的处理---参数1:通知
-(void)dealWithNotify:(NSNotification*)notification{
    self.label.text = notification.userInfo[@"zlzNotificationKey"];
}

(2)发送方 NextViewController

  • 在 NextViewController.m 的返回点击事件中发送通知
-(void)zlzBackClick{
    
   
    //通知传值---发送通知
    //object:nil表示群发
    [[NSNotificationCenter defaultCenter]postNotificationName:@"zlzNotify" object:nil userInfo:@{@"zlzNotificationKey":self.textFiled.text}];
    
    
    
    // dismissViewControllerAnimated:animated:completion:
    //用来 关闭当前视图控制器 的方法,通常用于关闭通过 presentViewController:animated:completion: 模态展示的视图控制器
    //completion:nil:表示关闭完成后执行的回调
    [self dismissViewControllerAnimated:YES completion:nil];
}

3、总结

属性传值简单的正向传值,不能跨页面传值
单例传值可以正向反向传值,可以跨页面,但是需要创建一个单例对象
NSUserDefaults传值类似单例传值,区别是单例传值是把值写入内存,而它是把值写入沙盒文件
代理传值主要用于反向传值,一对一,必须两个页面建立代理关系
block传值

主要用于反向传值,一对一

代理传值能做的它都能做,但他不能取代代理传值

通知传值可以跨页面传值,多对多

;