• iOS开发中视图控制器ViewControllers之间的数据传递


    iOS开发中视图控制器ViewControllers之间的数据传递

    这里我们用一个demo来说明ios是如何在视图控制器之间传递重要的参数的。本文先从手写UI来讨论,在下一篇文章中讨论在storyboard中传递数据。

    首先新建一个空工程,并添加一个根视图控制器类,如下图所示:

    #

    在函数didFinishLunchingWithOption中添加几行代码,完成后如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        // Override point for customization after application launch.
        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
         
        RootViewController *myRootViewController = [[RootViewController alloc] init];
        myRootViewController.view.backgroundColor = [UIColor lightGrayColor];
        self.window.rootViewController = myRootViewController;
        return YES;
    }


    完成以后运行,iOS模拟器显示结果如下:

    #

    由图中可以看出,我们自定义的myRootViewController已经成功在启动时加载,显示出了一个浅灰色的界面。

    随后如法炮制新建另一个viewController命名为FirstSubViewController,同时在RootViewController的viewDidLoad函数中添加如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        UIButton *firstVC = [UIButton buttonWithType:UIButtonTypeSystem];
        firstVC.frame = CGRectMake(60, 244, 200, 80);
        [firstVC setTitle:@"显示下一个视图" forState:UIControlStateNormal];
        [firstVC addTarget:self action:@selector(displayNextViewController) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:firstVC];
    }

    之后还需定义一个函数,名为displayNextViewController,函数体暂时设为空。此时运行程序,界面中央将显示一个按钮“显示下一个视图”,但是单击该按钮没有任何反应。这是因为响应函数displayNextViewController还没有实现。现在在该函数中添加代码:

    1
    2
    3
    4
    5
    6
    7
    - (void)displayNextViewController
    {
        FirstSubViewController *firstSubVC = [[FirstSubViewController alloc] init];
        [self presentViewController:firstSubVC animated:YES completion:^{
            NSLog(@"present first sub VC ok");
        }];
    }


    完成后运行程序发现,按钮已经有反应了,按下后回出现一个新的白色背景的新界面,这就是我们在这里定义的firstSubVC;

    下一步实现界面的返回操作。在FirstSubViewController的viewDidLoad函数中建立一个回退按钮,并实现其响应函数。代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
         
        UIButton *goBack = [UIButton buttonWithType:UIButtonTypeSystem];
        goBack.frame = CGRectMake(60, 244, 200, 80);
        [goBack setTitle:@"返回上级界面" forState:UIControlStateNormal];
        [goBack addTarget:self action:@selector(goBackToPreviousViewController) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:goBack];
    }
     
    - (void)goBackToPreviousViewController
    {
        [self dismissViewControllerAnimated:YES completion:^{
            NSLog(@"Back to previous OK");
        }];
    }


    到此为止,我们已经通过presentViewController和dismissViewController实现了视图的切换,下面来考虑两个视图控制器之间的数据交流的问题。

    在此之前,分别在RootViewController和FirstSubViewController中添加一个标签和文本框,作为数据的显示和输入部分。我们的目的是在FirstSubViewController中输入一个数字,然后再RootViewController显示出来。

    在这两个类中分别用property来实现文本框和标签栏:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    //RootViewController.m
    @interface RootViewController ()
     
    @property (strong,nonatomic) UILabel *lable;
     
    @end
     
    @implementation RootViewController
     
    - (UILabel *)lable
    {
        if (!_lable)
        {
            _lable= [[UILabel alloc] initWithFrame:CGRectMake(60, 150, 200, 30)];
            _lable.textAlignment = NSTextAlignmentCenter;
            _lable.text = @"Hello World!";
            _lable.backgroundColor = [UIColor whiteColor];
        }
        return _lable;
    }
    …..
    @end
     
    //FirstSubViewController
    @interface FirstSubViewController ()
     
    @property (strong,nonatomic) UITextField *inputText;
     
    @end
     
    @implementation FirstSubViewController
     
    - (UITextField *)inputText
    {
        if (!_inputText)
        {
            _inputText = [[UITextField alloc] initWithFrame:CGRectMake(60, 150, 200, 30)];
            _inputText.backgroundColor = [UIColor lightGrayColor];
        }
        return _inputText;
    }
    …..
    @end



    在这两个视图控制器的viewDidLoad中分别添加如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //RootViewController.m
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        [self.view addSubview:self.label];
         
        UIButton *firstVC = [UIButton buttonWithType:UIButtonTypeSystem];
        …..
    }
    …..
    //FirstSubViewController
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
         
        //添加输入框
        [self.view addSubview:self.inputText];
        UIButton *goBack = [UIButton buttonWithType:UIButtonTypeSystem];
        …..
    }

    在视图控制器之间进行数据传递可以通过多种方法,下面将逐个实验:

    1、使用代理delegate的方法:

    基本原理:FirstSubViewControllers试图改变RootViewController的数据,但是除了操作自己内部的数据的能力之外,不能改变其他类的数据。想要将这些数据传递出去,需要设置代理方法,获取FirstSubViewControllers中数据的类来遵循该方法,通过实现该代理协议中的方法来获取FirstSubViewControllers中的数据。

    具体步骤:

    首先在FirstSubViewController.h中定义协议:

    1
    2
    3
    4
    5
    6
    @protocol FirstSubViewControllerDelegate <nsobject>
     
    @optional
    - (void)getStringFromFirstSubViewControllerDelegate:(NSString *)outputString;
     
    @end</nsobject>


    然后添加一个符合该协议的代理属性:

    1
    2
    @property (nonatomic,weak) id<firstsubviewcontrollerdelegate> delegate;
    </firstsubviewcontrollerdelegate>


    在RootViewControlller.h中,声明该类符合FirstSubViewControllerDelegate协议:

    1
    @interface RootViewController : UIViewController<firstsubviewcontrollerdelegate></firstsubviewcontrollerdelegate>


    在新建FirstSubViewController的实例后,将其delegate属性定义为self,同时实现协议中的方法,两个函数如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    - (void)getStringFromFirstSubViewControllerDelegate:(NSString *)outputString
    {
        self.lable.text = outputString;
    }
     
    - (void)displayNextViewController
    {
        FirstSubViewController *firstSubVC = [[FirstSubViewController alloc] init];
        firstSubVC.delegate = self;
        [self presentViewController:firstSubVC animated:YES completion:^{
            NSLog(@"present first sub VC ok");
        }];
    }


    最后在FirstSubViewController.m的goBackToPreviousViewController中添加一句向delegate属性发送获取数据的消息:

    1
    2
    3
    4
    5
    6
    7
    - (void)goBackToPreviousViewController
    {
        [self.delegate getStringFromFirstSubViewControllerDelegate:self.inputText.text];
        [self dismissViewControllerAnimated:YES completion:^{
            NSLog(@"Back to previous OK");
        }];
    }

    这样,大功告成了,在FirstSubViewController中的输入框中输入的内容,在按返回按钮后回显示在第一个界面的标签上。

    2、使用通知Notification的方法

    关于通知的知识在未来将会详述,在这里只是简要介绍一种使用通知这一机制的方法。

    在使用通知之前,必须在默认通知中心里添加一个所谓“观察者”和通知,这个通知是命名的,同时还指定了回调的方法。当该通知中心收到了某个对象发送了相应的通知时,将会调用指定的方法执行某项操作。通知的发送者同时还可以发送相应的消息作为通知的参数。

    注册通知中心可以在RootViewController.m中的viewDidLoad函数的末尾添加如下函数:

    1
    2
    //使用通知的方式实现
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeLabelText:) name:@"ChangeLabelTextNotification" object:Nil];

    此外还要实现观察者的回调函数:

    1
    2
    3
    4
    5
    - (void)changeLabelText:(NSNotification *)notification
    {
        id text = notification.object;
        _lable.text = text;
    }

    自此通知的接收端已经完成。

    通知的发送端,只需在“返回上级界面”的相应函数中按照事先定义的名称发送通知和参数即可:

    1
    2
    //使用通知方式实现
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ChangeLabelTextNotification" object:_inputText.text];

    此时运行,将会发现和代理模式起到了相同的作用。

    除了代理和通知之外,还有其他如KVO等方法,未来还会详细探讨。

  • 相关阅读:
    js基础 数组reduce
    js基础 数组every some
    js基础 数组forEach
    js基础 数组排序
    js基础 数组findIndex
    nodejs+koa2微信app支付,小程序支付
    Iview-datePicker获取选中的日期,如果没有选,提示错误,选了,错误隐藏
    mongoose+koa2 按照_id更新多条数据,删除数组中的字段,然后添加新的字段,$pull和$or结合使用
    json数组去除重复的值
    mongoose根据_id更新,且如果数组中没有元素就添加
  • 原文地址:https://www.cnblogs.com/jiwangbujiu/p/5400442.html
Copyright © 2020-2023  润新知