• iOS学习之六种传值方式


    iOS页面传值方式

    应用于:

    1. 两个互动的界面:1)页面一跳转到页面二,页面一的textField的值传给页面二的label。2)A页面跳转到B页面,B页面再跳转回A页面(注册页面跟登录页面)
    2. 两个不互动的两个界面:数据持久层跟表示层的数据交互。

    几种传值方式:

    1. 属性传值 
    2. 委托delegate方式
    3. 通知notification方式
    4. block方式
    5. 单例模式方式
    6. UserDefault或者文件方式

    1.属性传值(顺传):

    1. 需要定义一个公开的属性
    2. 需要一个你需要传值的对象
    3. 进行属性赋值

    实现:A、B两个界面,通过按钮将A界面textField的值传给页面B的label。

    A:ViewController   B:DetailViewController

    #import "ViewController.h"
    
      @interface ViewController ()
    
      @property (nonatomic, strong) UITextField *textField;
    
     @end
    
      @implementation ViewController
    
    -(void)buttonAction:(UIButton *)button
    
    {
    
    DetailViewController *detailViewController = 
    
    [[DetailViewController alloc]init];//用下一个视图的属性接受想要传过去的值,属性传值
    
    detailViewController.firstValue = self.txtFiled.text;
    
    [self.navigationController pushViewController:second animated:YES];
    
    }
    
    DetailViewController界面
    
    #import "DetailViewController.h"
    
      @interface DetailViewController ()
    
      @property (nonatomic, weak) NSString firstValue;//接收textField传过来的值。
    
     @end

    2.代理传值(顺传倒传都可以)

    delegate只能是一对一之间的。他只能是navigation的栈里面的相邻控制器传值, 不能跨控制器传值。比如:a到b,b到c.,而不能从c传到a.

    1. 拟定⼀份协议(命名一般是XXXDelegate),协议里面的⽅法的参数取决于你要传递的内容
    2. 设置代理人属性(再次强调,使用assign防⽌循环引用)
    3. 在需要调⽤的地⽅调⽤,这⼀步比较抽象,⽐如上面所讲例⼦子,我们是需要在button点击的时候
    4. 传值并且取消界面,所以我们的delegate就在这个⽅面的进⾏调用
    5. 让相应的对象成为代理人,⼀般都是在创建的时候指定一个代理⼈
    6. 遵守协议,并且实现相应的方法,然后在方法中进行逻辑处理

    实现:A页面push到B页面,如果 B页面的信息想回传(回调)到A页面,用代理传值,其中B定义协议和声明代理,A确认并实现代理,A作为B的代理

    A页面:RootViewControllers  B页面:DetailViewControllers

    ViewControllers.h文件
    
    #import <UIKit/Uikit.h>
    
    @class DetailViewController;
    
    @protocol PassingValueDelegate<NSObject>//拟定协议
    
    @optional
    
    -(void)passValues:(NSString *)values;//定义协议方法(values你想要传递的内容)
    
    @end
    
    @interface ViewControllers: UIViewController
    
    @property (nonatomic, weak)id< PassingValueDelegate > delegate; (valueDelegate)//设置代理属性,通过其传值(为防止循环引用,此处采用了weak或者assign)
    
    点击按钮事件函数(调用代理)
    
    -(void)trendBtnClick{ 
    
        //create the view 
    
      DetailViewController * detailViewController = [[DetailViewController alloc] initWithNibName:@" DetailViewController " bundle:nil]; //传值并且取消界面
    
        self.delegate (自己命名的valueDelegate )= detailViewController; //设置代理 ,让相应的对象成为代理人
    
        [self.trendDelegate passValues:@"123456"]; 
    
    //页面跳转  
    
    }
    
    DetailViewController.h 文件
    
    引用ViewController的头文件,并添加代理协议如下
    
    #import "ViewController.h" 
    
    @interface TrendViewController : UIViewController<PassTrendValueDelegate>{ 
    
    } 
    
    @end
    
    实现代理函数:
    
    #pragma mark 实现传值协议方法 
    
    -(void)passValues:(NSString *)values{ 
    
    NSLog(@"values=%@",values);  
    
    }

    最重要也是最容易忽略的,就是一定要设置delegate的指向

    3.通知传值(顺传倒传都可以)第三个页面的值传给第一个页面

    谁要监听值的变化,谁就注册通知 ,特别要注意,通知的接受者必须存在这一先决条件不用通知的时候,记得移除。

    1. 在第三个界面中, 建⽴一个通知中心, 通过通知中心, 发送通知(发送通知的过程就是传值的过程,将要传输的值作为object的值传给第一个界面
    2. 在第⼀个界面建⽴一个通知中心, 通过通知中⼼,注册一个监听事件
    3. 在第一个界⾯中,设置接收到通知的事件。
    4. 在第⼀个界⾯面中的dealloc中, 将通知中心remove掉

    任何对象对可以发送通知到中心,同时任何对象可以监听中心的通知。
    发送通知的代码如下:

    [[NSNotificationCenter defaultCenter] postNotificationName:@”myNotificationName” object:broadcasterObject]; 

    注册接收通知的代码如下: 

    [[NSNotificationCenter defaultCenter] addObserver:listenerObject selector:@selector(receivingMethodOnListener:) name:@”myNotificationName” object:nil]; 

    实现:将B界面的值传给A界面,所以B界面发送通知到通知中心,A界面注册成为监听者,监听B值的变化,接受从通知中心回传的B的值。如果c页面也想接受B的值,也同样注册成为监听者就行。(所以可以实现多对多)

    A界面:RootViewController B界面:SecondViewController

    B界面建立通知中心,将要传的值nameTextField.text通过通知中心发送

    //SecondViewController.m
    
    -(IBAction)notificationMethod:(id)sender {
    
    [[NSNotificationCenter defaultCenter] postNotificationName:@'ChangeNameNotification'  object:self  userInfo:@{@'name':self.nameTextField.text}];
    
    [self dismissViewControllerAnimated:YES completion:nil];
    
    }
    
    在A页面的控制器中,注册通知:
    
    //RootViewController.m
    
    - (void)viewDidLoad.{
    
    [super viewDidLoad];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ChangeNameNotification:) name:@'ChangeNameNotification' object:nil];
    
    }
    
    调用,显示
    
    //RootViewController.m
    
    -(void)ChangeNameNotification:(NSNotification*)notification{
    
    NSDictionary *nameDictionary = [notification userInfo];
    
    self.nameLabel.text = [nameDictionary objectForKey:@'name'];
    
    .}
    
    当我们不使用时,要记得删掉通知:
    
    //RootViewController.m
    
    -(void)dealloc{
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    }
    

    4. block传值(顺传倒传都可以)block同样用于回调

    1. 为block取别名。并且在参数列表中将需要传递的参数写形参
    2. 设置block属性(注意使用copy)
    3. 设置一个方法持有当前block
    4. 在合适的地方进行调用类似代理
    5. 在创建该对象的地方进行block方面的调用

    //block语法

       //返回值类型 (^block参数名) (参数类型 参数名) = ^返回值类型 (参数类型 参数名)

    实现:将B界面的textField.text传给A界面的Label

    A页面:RootViewControllers  B页面:DetailViewControllers

    DetailViewController文件

    #import <UIKit/Uikit.h>
    
    typedef void (^DetailBlock)(NSString *);//block取别名。并且在参数列表中将需要传递的参数写形参
    
    @interface DetailViewController : UIViewController
    
    @property (nonatomic, copy) PassingValueBlock passingvalue;//设置block属性(注意使用copy)
    
    @property (weak, nonatomic) UITextField *inputTF;
    
    @end
    
    - (IBAction)BtnAction:(id)sender {    
    
        //判断block是否为空
    
        if (self.NextViewControllerBlock) {
    
            self.NextViewControllerBlock(self.inputTF.text);       
    
        }
    
        [self.navigationController popViewControllerAnimated:YES];
    
    }//点击按钮到A界面
    
    RootViewController.m
    
    @property (strong, nonatomic) UILabel *textLabel;
    
     
    
    -(void)handleButton: (NSString*)sender{
    DetailViewController *detailViewController = [[DetailViewController alloc]init];
    
    detailViewController.passingValue=^( NSString* str){
    self. textLabel.text= str;}
    
    [self.navigationController pushViewController:detailViewController animated:YES];
    
    }

    5. 单例传值(顺传倒传都可以)

    单例的好处就在于只是创建了一次,其余任何时候访问到的对象都是同一个,所以很多时候用到用户的一些信息都是保存在单例中的,这样就不需要多次传值了,只需要再次创建单例就可以了

    AppStatus.h  创建一个单例类 AppStatus

    #import <Foundation/Foundation.h>
    
    @interface AppStatus : NSObject
    
    {
    
        NSString *_contextStr;
    
    }
    
    @property(nonatomic,retain)NSString *contextStr;
    
    +(AppStatus *)shareInstance;
    
    @end
    
    AppStatus.m
    
    #import "AppStatus.h"
    
    @implementation AppStatus
    
    @synthesize contextStr = _contextStr;
    
    static AppStatus *_instance = nil;
    
     
    
    +(AppStatus *)shareInstance
    
    {
    
        if (_instance == nil)
    
        {
    
            _instance = [[super alloc]init];
    
        }
    
        return _instance;
    
    }
    
    -(id)init
    
    {
    
        if (self = [super init])
    
        {       
    
        }
    
        return self;
    
    }
    
    @end
    
    RootViewController.h
    
    #import "RootViewController.h"
    
    #import "DetailViewController.h"
    
    #import "AppStatus.h"
    
     
    
    @interface RootViewController ()
    
     
    
    @end
    
     
    
    @implementation RootViewController
    
     
    
    -(void)pushAction:(id)sender
    
    {
    
        tf = (UITextField *)[self.view viewWithTag:1000];
    
     
    
     //单例传值  将要传递的信息存入单例中(共享中)
    
      //  [[AppStatus shareInstance]setContextStr:tf.text]; 跟下面这种写法是等价的
    
        [AppStatus shareInstance].contextStr = tf.text;
    
        //导航push到下一个页面
    
        
    
        DetailViewController *detailViewController = [[DetailViewController alloc]init];
    
     
    
        //导航push到下一个页面
    
        [self.navigationController pushViewController:detailViewController animated:YES];
    
    } 
    
     
    
    @end
    
    DetailViewController.h
    
    #import <UIKit/UIKit.h>
    
    @protocol ChangeDelegate;//通知编译器有此代理
    
     
    
    @interface DetailViewController : UIViewController
    
    {
    
        UITextField *textField;
    
    }
    
     
    
    @end
    
    #import "DetailViewController.h"
    
    #import "AppStatus.h"
    
     
    
    @interface DetailViewController ()
    
     
    
    @end
    
     
    
    @implementation DetailViewController
    
     
    
    @synthesize naviTitle = _naviTitle;
    
     
    
    -(void)loadView
    
    {
    
        self.view = [[[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)]autorelease];
    
     
    
        //单例
    
        self.title = [AppStatus shareInstance].contextStr;
    
        textField = [[UITextField alloc]initWithFrame:CGRectMake(100, 100, 150, 30)];
    
        textField.borderStyle = UITextBorderStyleLine;
    
        [self.view addSubview:textField];
    
     
    
        UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDonetarget:self action:@selector(doneAction:)];
    
        self.navigationItem.rightBarButtonItem = doneItem;
    
        [doneItem release];
    
    }
    
     
    
    //这个方法是执行多遍的  相当于刷新view
    
    -(void)viewWillAppear:(BOOL)animated
    
    {
    
        [super viewWillAppear:animated];
    
        tf = (UITextField *)[self.view viewWithTag:1000];
    
        tf.text = [AppStatus shareInstance].contextStr;
    
    }
    
     
    
    //pop回前一个页面
    
    -(void)doneAction:(id)sender
    
    {
    
        //单例传值
    
        [AppStatus shareInstance].contextStr = textField.text;
    
        [self.navigationController popToRootViewControllerAnimated:YES];
    
    }

    6.NSUserDefault传值(顺传倒传都行)

    [[NSUSerDefault  standardUserDefaults]setObject:要传的值   forKey:对这个值得标记键];//设置值

    [[NSUserDefault  standardUserDefaults]ObjectForKey:根据你的标记键];//获取值

  • 相关阅读:
    c++单例模式为什么不在析构函数中释放静态的单例对象(转)
    Ubuntu 树莓派2b交叉编译环境
    多线程std::cout 深入研究
    c++11的 move并没有实际move
    RTC时间设置
    QT 第三方串口库COM10以上无法读取问题
    ubuntu gcc-5 安装
    STM32正交编码器驱动电机
    (转)layoutSubviews总结
    自定义视图控制器切换(iOS)
  • 原文地址:https://www.cnblogs.com/bzhong/p/5979064.html
Copyright © 2020-2023  润新知