在视图控制器之间传递数据

我是iOS和Objective-C以及整个MVC范例的新手,我坚持以下几点:

我有一个视图用作数据输入表单,我想让用户选择多个产品。 使用UITableViewController将产品列在另一个视图中,并且已启用多个选择。

我的问题是,如何将数据从一个视图传输到另一个视图? 我将在数组中保存UITableView的选择,但是如何将它们传递回先前的数据输入表单视图,以便在提交表单时将其与其他数据一起保存到核心数据中?

我浏览过周围,看到有些人在应用程序委托中声明了一个数组。 我读了一些关于单身人士的东西,但不明白这些是什么,我读了一些关于创建数据模型的东西。

执行此操作的正确方法是什么?我将如何处理它?


这个问题似乎在stackoverflow上很受欢迎,所以我想我会尝试给出一个更好的答案,以帮助像我这样的iOS开始。

我希望这个答案足够清晰,让人们明白,并且我没有遗漏任何东西。

向前传递数据

将数据从另一个视图控制器传递给视图控制器。 如果你想将一个对象/值从一个视图控制器传递到另一个视图控制器,你可能会使用这种方法。

对于这个例子,我们将有ViewControllerAViewControllerB

要将ViewControllerABOOL值传递给ViewControllerB我们将执行以下操作。

  • ViewControllerB.hBOOL创建一个属性

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  • ViewControllerA你需要告诉它关于ViewControllerB所以使用一个

    #import "ViewControllerB.h"
    

    然后,你想加载视图,例如。 didSelectRowAtIndex或一些IBAction您需要先在ViewControllerB设置属性,然后再将其推入导航堆栈。

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.isSomethingEnabled = YES;
    [self pushViewController:viewControllerB animated:YES];
    

    这会将ViewControllerB isSomethingEnabled设置为BOOLYES

  • 使用分段传递数据转发

    如果你正在使用故事板,你很可能会使用segues,并且需要这个过程来传递数据。 这与上述类似,但不是在推送视图控制器之前传递数据,而是使用名为的方法

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    

    所以要通过一个BOOLViewControllerAViewControllerB我们会做到以下几点:

  • ViewControllerB.hBOOL创建一个属性

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  • ViewControllerA你需要告诉它关于ViewControllerB所以使用一个

    #import "ViewControllerB.h"
    
  • 在Storyboard上创建一个从ViewControllerAViewControllerB的segue并给它一个标识符,在这个例子中,我们将它称为"showDetailSegue"

  • 接下来,我们需要将该方法添加到在执行任何Segue时调用的ViewControllerA ,因此我们需要检测哪个segue被调用,然后执行某些操作。 在我们的例子中,我们将检查"showDetailSegue" ,如果这样做,我们将传递BOOL值到ViewControllerB

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    

    如果您将视图嵌入到导航控制器中,则需要将上面的方法略微更改为以下方法

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
            ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    

    这会将ViewControllerB isSomethingEnabled设置为BOOLYES

  • 传回数据

    传递数据从背面ViewControllerBViewControllerA需要使用协议和代表或块,后者可以被用作用于回调松散耦合机制。

    要做到这一点,我们将ViewControllerA的委托ViewControllerB 。 这允许ViewControllerB将消息发送回ViewControllerA使我们能够发回数据。

    对于ViewControllerA是的代表ViewControllerB它必须符合ViewControllerB我们有指定的协议。 这告诉ViewControllerA它必须实现哪些方法。

  • ViewControllerB.h#import下方,但上面的@interface指定协议。

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
    
  • 接下来仍然在ViewControllerB.h您需要设置一个delegate属性并在ViewControllerB.m合成

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
    
  • ViewControllerB ,当我们弹出视图控制器时,我们在delegate上调用一条消息。

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
    
  • 这就是ViewControllerB 。 现在在ViewControllerA.h ,告诉ViewControllerA导入ViewControllerB并符合它的协议。

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
    
  • ViewControllerA.m从我们的协议实现以下方法

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
    
  • 在将viewControllerBviewControllerB导航堆栈之前,我们需要告诉ViewControllerB ViewControllerA是它的委托,否则我们会得到一个错误。

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.delegate = self
    [[self navigationController] pushViewController:viewControllerB animated:YES];
    

  • 参考

  • 在View Controller编程指南中使用委托与其他视图控制器通信
  • 委托模式

  • 迅速

    这里和周围有大量的解释和StackOverflow,但如果你是一个初学者,试图让一些基本的工作,尝试看这个YouTube教程(这是什么帮助我终于明白如何做到这一点)。

  • YouTube教程:如何通过segue(swift)发送数据
  • 将数据传递给下一个View Controller

    以下是基于视频的示例。 这个想法是将字符串从第一个视图控制器的文本字段传递到第二个视图控制器中的标签。

    在这里输入图像描述

    在Interface Builder中创建故事板布局。 要进行搜寻,只需按住按钮并拖至第二个视图控制器。

    第一视图控制器

    第一个视图控制器的代码是

    import UIKit
    
    class FirstViewController: UIViewController {
    
        @IBOutlet weak var textField: UITextField!
    
        // This function is called before the segue
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    
            // get a reference to the second view controller
            let secondViewController = segue.destination as! SecondViewController
    
            // set a variable in the second view controller with the String to pass
            secondViewController.receivedString = textField.text!
        }
    
    }
    

    第二视图控制器

    第二个视图控制器的代码是

    import UIKit
    
    class SecondViewController: UIViewController {
    
        @IBOutlet weak var label: UILabel!
    
        // This variable will hold the data being passed from the First View Controller
        var receivedString = ""
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // Used the text from the First View Controller to set the label
            label.text = receivedString
        }
    
    }
    

    别忘了

  • 连接UITextFieldUILabel的插座。
  • 将第一个和第二个视图控制器设置为IB中合适的Swift文件。
  • 将数据传递回先前的View Controller

    要将数据从第二个视图控制器传回第一个视图控制器,可以使用协议和委托。 该视频非常清晰地描述了这一过程:

  • YouTube教程:iOS Swift基础教程:协议和代表但是也请阅读这篇文章,以确保您不会进入强大的参考周期。
  • 以下是基于视频的示例(仅做了一些修改)。

    在这里输入图像描述

    在Interface Builder中创建故事板布局。 再次,为了使segue,你只需控制从按钮拖动到第二个视图控制器。 将segue标识符设置为showSecondViewController 。 此外,不要忘记使用以下代码中的名称来连接插座和操作。

    第一视图控制器

    第一个视图控制器的代码是

    import UIKit
    
    class FirstViewController: UIViewController, DataEnteredDelegate {
    
        @IBOutlet weak var label: UILabel!
    
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if segue.identifier == "showSecondViewController" {
                let secondViewController = segue.destination as! SecondViewController
                secondViewController.delegate = self
            }
        }
    
        func userDidEnterInformation(info: String) {
            label.text = info
        }
    }
    

    请注意使用我们自定义的DataEnteredDelegate协议。

    第二个视图控制器和协议

    第二个视图控制器的代码是

    import UIKit
    
    // protocol used for sending data back
    protocol DataEnteredDelegate: class {
        func userDidEnterInformation(info: String)
    }
    
    class SecondViewController: UIViewController {
    
        // making this a weak variable so that it won't create a strong reference cycle
        weak var delegate: DataEnteredDelegate? = nil
    
        @IBOutlet weak var textField: UITextField!
    
        @IBAction func sendTextBackButton(sender: AnyObject) {
    
            // call this method on whichever class implements our delegate protocol
            delegate?.userDidEnterInformation(info: textField.text!)
    
            // go back to the previous view controller
            _ = self.navigationController?.popViewController(animated: true)
        }
    }
    

    请注意, protocol不在View Controller类中。

    而已。 现在运行应用程序,您应该可以将数据从第二个视图控制器发送回第一个。


    MVC中的M用于“模型”,而在MVC范例中,模型类的作用是管理程序的数据。 模型与视图相反 - 视图知道如何显示数据,但不知道如何处理数据,而模型知道如何处理数据的所有信息,但不知道如何显示数据。 模型可能很复杂,但它们不一定是 - 应用程序的模型可能与字符串或字典数组一样简单。

    控制器的作用是在视图和模型之间进行调解。 因此,他们需要对一个或多个视图对象和一个或多个模型对象的引用。 假设你的模型是一个字典数组,每个字典代表你表中的一行。 您的应用的根视图显示该表,并且它可能负责从文件加载数组。 当用户决定向表中添加一个新行时,他们点击一些按钮,您的控制器创建一个新的(可变的)字典并将其添加到数组中。 为了填写行,控制器创建一个详细视图控制器并为其提供新的字典。 详细视图控制器填写字典并返回。 字典已经是模型的一部分,所以没有别的事情需要发生。

    链接地址: http://www.djcxy.com/p/3495.html

    上一篇: Passing Data between View Controllers

    下一篇: What's your most controversial programming opinion?