【问题标题】:Pass data through navigation back button通过导航返回按钮传递数据
【发布时间】:2016-04-29 14:25:42
【问题描述】:

我处于这种情况:

我使用prepare for segue将4个数组从进度表传递到详细练习,它工作正常!当我尝试将数据从详细练习控制器传递回进度表控制器时,问题就开始了。我想使用默认的导航返回按钮返回父视图。实际上我正在使用此代码但它不起作用,数据从子视图传递到父视图但我在进度表中看不到结果,似乎我需要刷新但我也尝试了 reloadData在 viewDidLoad 之后它不起作用。有什么建议吗?谢谢。

override func viewWillDisappear(animated : Bool) {
    super.viewWillDisappear(animated)

    if (self.isMovingFromParentViewController()){
        print("n'drio")

        let historyView = self.storyboard!.instantiateViewControllerWithIdentifier("historyView") as! HistoryTableViewController
        historyView.isFirstTime = false
        historyView.arrayData = arrayDataDetails
        historyView.arrayRipetizioni = arrayRipetizioniDetails
        historyView.arrayPeso = arrayPesoDetails
        historyView.arrayRecupero = arrayRecuperoDetails
        historyView.tableView.reloadData()
    }
}

【问题讨论】:

  • 除了将其传回之外,您还可以考虑创建一个自定义类,将数组作为类属性,这样每当您在练习视图控制器中更改它们时,它们也会在进度视图控制器中更改。

标签: ios swift uinavigationcontroller pass-data


【解决方案1】:

当您按下返回按钮时,导航控制器将调用navigationController(willShowViewController:),因此您可以使用它将数据传回初始视图控制器。示例如下:

使用UINavigationControllerDelegate

class DetailsViewController: UIViewController, UINavigationControllerDelegate {
                                                        //     ^
    var data: [String] = []                             // Important!

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationController?.delegate = self

        data = ["data has changed!"]
    }
}

斯威夫特 2:

extension DetailsViewController: UINavigationControllerDelegate {
    func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
        if let controller = viewController as? ProgressTableViewController {
            controller.data = data    // Here you pass the data back to your original view controller
        }
    }
}

斯威夫特 3:

extension DetailsViewController: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        (viewController as? ProgressTableViewController)?.data = data // Here you pass the to your original view controller
    }
}

在本例中,关键是使用UINavigationControllerDelegate 并设置导航控制器的委托(在本例中为self)。完成此操作后,您可以使用返回按钮将数据发送回初始视图控制器。

我个人更喜欢为我的数据使用一个类:

为您的数据使用自定义类:

class Data {
    var array: [String] = []
}

进度视图控制器:

class ProgressTableViewController: UITableViewController {

    var data = Data()

    override func viewDidLoad() {
        super.viewDidLoad()

        data.array = ["some data"]
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        tableView.reloadData()
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.array.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()

        cell.textLabel?.text = data.array[indexPath.row]

        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "exerciseSegue", sender: self)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "exerciseSegue" {
            let destination = segue.destinationViewController as! DetailsViewController
            destination.data = data
        }
    }
}

详情视图控制器:

class DetailsViewController: UIViewController {

    var data = Data()

    override func viewDidLoad() {
        super.viewDidLoad()

        data.array = ["data has changed!"]
    }
}

在最后一个示例中,您不必担心传递数据。每当您更改数据时,使用相同类的控制器也会发生更改。

【讨论】:

  • 感谢您的回答,我选择了“桥梁”类的方式,效果很好!非常感谢!
  • 今天学到了一个新东西。非常感谢 Eendje :)
  • 为什么投反对票?想知道,所以我可以纠正它。
  • 我喜欢第一个例子!
  • 当我从扩展中删除多余的UINavigationControllerDelegate 后,第一个示例就起作用了。
【解决方案2】:

通常,协议和委托用于在屏幕之间来回传递数据。

// Define a delegate that is known to both view controllers
protocol DetailsExerciseDelegate {
    func detailsWillDisappear(...);
}

class DetailsExerciseViewController {
    // Accept the delegate as a property on the details view controller
    var delegate : DetailsExerciseDelegate

    override func viewWillDisappear(animated : Bool) {
        super.viewWillDisappear(animated)

        // When you want to send data back to the caller
        // call the method on the delegate
        if let delegate = self.delegate {
            delegate.detailsWillDisappear(/* your data in one or more parameters */)
        }
    }
}

// Implement the delegate by adding the required function
class ProgressTableViewController: DetailsExerciseDelegate {
    ...

    func detailsWillDisappear(...) {
        // When the child calls the function, update the screen
        historyView.isFirstTime = false
        historyView.arrayData = arrayDataDetails
        historyView.arrayRipetizioni = arrayRipetizioniDetails
        historyView.arrayPeso = arrayPesoDetails
        historyView.arrayRecupero = arrayRecuperoDetails
        historyView.tableView.reloadData()
    }

    override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
        if segue!.identifier == "DetailsExcercise" {
            // And finally, when launching the child view,
            // make sure to set the delegate.
            let viewController = segue!.destinationViewController as DetailsExerciseViewController
            viewController.delegate = self
        }
    }
}

话虽如此,单击后退按钮时尝试保存数据似乎是不标准的。您确定不想改为在“完成”上执行此操作吗?

【讨论】:

  • 感谢您回答我的问题,但您的代码根本无法理解!在func detailsWillDisappear 如何将数据传回父视图?你在哪里初始化historyView??
  • 请记住,您的类DetailsExerciseViewController 将有一个强引用循环,因为委托会阻止它被释放。将其设为weak 将解决此问题。
  • 正如@Eendje 在他的评论中所说,您需要使用弱引用来实现委托以避免任何保留周期
  • @Eendje 对不起,我是协议和代表的新手,您能否用一些代码示例回答我的问题以解决我的问题。非常感谢!
【解决方案3】:

更简单的解决方案,您可以使用 self.navigationController?.viewControllers 访问以前的视图控制器,如下所示:

let vcsCount = self.navigationController?.viewControllers.count
self.navigationController?.viewControllers[vcsCount! - 2].updateData

updateData 是前一个视图控制器要更新的数据成员

【讨论】:

    【解决方案4】:

    另外,你可以使用这个扩展:

    extension UINavigationController {
        func viewController<T: UIViewController>(class: T.Type) -> T? {
    
            return viewControllers.filter({$0 is T}).first as? T
        }
    }
    
    //
    
    if let controller = navigationController?.viewController(class: MainViewController.self) {
         controller.data = data
    }
    
    navigationController?.popViewController(animated: true)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-11
      • 1970-01-01
      相关资源
      最近更新 更多