【问题标题】:Passing Data in Swift在 Swift 中传递数据
【发布时间】:2014-06-20 00:56:39
【问题描述】:

我一直在寻找这个问题的答案,但只找到了 segues 的答案。

我有一个 viewController1 和一个连接到 viewController2 的按钮。这个没有代码,我是通过Interface builder设置的。在viewController2 上,我有一个按钮会自行关闭

 self.dismissViewControllerAnimated(true, completion, nil)

当视图被关闭时,我想将一个字符串从viewController2 传递回viewController1。我该怎么做呢?另外,我正在使用 swift。

提前致谢!

【问题讨论】:

    标签: model-view-controller swift ios8 xcode6


    【解决方案1】:

    有两种常见的模式,这两种模式都消除了 viewController2 明确了解 viewController1 的需要(这对可维护性很有好处):

    1. 为 viewController2 创建一个委托协议,并将 viewController1 设置为委托。每当您想将数据发送回 viewController1 时,让 viewController2 发送“委托”数据

    2. 将闭包设置为允许传递数据的属性。 viewController1 将在显示 viewController2 时在 viewController2 上实现该闭包。每当 viewController2 有数据要传回时,它就会调用闭包。感觉这个方法比较“快”似的。

    这是#2 的一些示例代码:

    class ViewController2 : UIViewController {
        var onDataAvailable : ((data: String) -> ())?
    
        func sendData(data: String) {
            // Whenever you want to send data back to viewController1, check
            // if the closure is implemented and then call it if it is
            self.onDataAvailable?(data: data)
        }
    }
    
    class ViewController1 : UIViewController {
       func doSomethingWithData(data: String) {
            // Do something with data
        }
        override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
            // When preparing for the segue, have viewController1 provide a closure for
            // onDataAvailable
            if let viewController = segue.destinationViewController as? ViewController2 {
                viewController.onDataAvailable = {[weak self]
                    (data) in
                    if let weakSelf = self {
                        weakSelf.doSomethingWithData(data)
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 这太棒了!有点像一个轻量级的内部协议。您可以使用可选链接来调用没有 if let... 的闭包:self.onDataAvailable?(data: data)
    • @NateCook 谢谢,关于可选链接的好电话。我更新了我的答案。
    • @user3724253 是的,它是ViewController2 的成员变量,它是一个闭包。您不会在其中“存储”您的字符串,而是在您希望 ViewController1 获取数据时用您的字符串调用它(就像一个函数)。我用ViewController2中的sendData方法给了你一个例子
    • @user3724253 您可以在闭包中访问“self”,但由于memory management issues,您必须将其用作弱引用,这会使事情变得更复杂一些。我更新了我的示例以向您展示。
    • @dewyze,在 ViewController1 被销毁后是否会在 ViewController2 上调用 onDataAvailable 取决于其余代码的编写方式。这里没有足够的代码/信息可以肯定地说,特别是因为我们不知道这些视图控制器是如何创建的,以及它们是否存储在其他任何地方。我们也不知道何时调用sendData。弱引用总是更安全,所以默认为弱引用总是一个好主意。
    【解决方案2】:

    我在没有 prepareForSegue 的控制器之间的转换中使用了第一个答案中的代码,并且也为我工作。 这是示例代码。

    第一个视图控制器:

    @IBAction func dpAgendaClick(sender:UIBarButtonItem) {
        ///instantiating view controller with identifier
        if let datePickerViewController = storyboard?.instantiateViewControllerWithIdentifier("DatePickerViewController") 
            as? DatePickerViewController {
                ///bring instantiated view controller to front
                self.presentViewController(datePickerViewController, animated: true, completion: nil)
                ///wrapping the data returned
                datePickerViewController.onDataFiltroAvailable = {[weak self]
                    (dataFiltro) in
                    if let weakSelf = self {
                        ///use dataFiltro here
                    }
    }
    

    第二个视图控制器:

    var onDataFiltroAvailable: ((dataFiltro: String) -> ())?
    ///private var
    var dataFiltro: String = ""
    ///the returning data is obtained on the datePickerChanged event
    @IBAction func datePickerChanged(sender: UIDatePicker) {
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
        dateFormatter.dateFormat = "yyyy-MM-dd"
        dataFiltro = dateFormatter.stringFromDate(datePicker.date)
    }
    
    ///dismiss the controller on button click
    @IBAction func dpOkClick(sender: UIButton) {
        ///"returning" the data
        self.onDataFiltroAvailable?(dataFiltro: dataFiltro)
        dismissViewControllerAnimated(true, completion: nil) 
    }
    

    【讨论】:

      【解决方案3】:

      (Swift 2.1、Xcode 7、iOS9) 如果您不希望它仅在 2 个 ViewController 之间紧密耦合, 您还可以使用通知设计模式(Post & Observe),主要用于将同一对象/信息从一个 VC 传递到多个 View Controller。

      对于您的场景: 在 VC2.swift 中:

      @IBAction func BackBtn(sender: UIButton) {  
        NSNotificationCenter.defaultCenter().postNotificationName("ThisIsTheMessage", object: nil, userInfo:["ObjectBeingSent":yourObject])
      
      }
      

      在 VC1.swift 中:

      override func viewDidLoad() {
              super.viewDidLoad()
              NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("yourFunction:"), name: "ThisIsTheMessage", object: nil)
          }
      
      
      
      func yourFunction(theNotification : NSNotification) {
      
                 if let extractInfo = theNotification.userInfo {
           //code to use the object sent from VC2, by extracting the object details
          }
           }
      

      常见的做法是:

      1. 向前传递数据 -> 使用 PrepareForSegue
      2. 向后传递数据到前一个视图控制器->协议和委托
      3. 跨多个视图控制器传递数据 -> 通知:发布和观察(在您使用对象详细信息的所有视图控制器中观察)

      【讨论】:

      • 问题-如果有人想在yourFunction()中设置一个等于返回的用户信息的字符串,该怎么做?
      • 对不起,我没有收到问题,请您补充一些详细信息
      猜你喜欢
      • 2017-02-22
      • 2018-11-23
      • 1970-01-01
      • 2022-12-29
      • 2017-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-05
      相关资源
      最近更新 更多