【问题标题】:How to pass data from child to parent view controller? in swift如何将数据从子视图控制器传递到父视图控制器?迅速
【发布时间】:2017-01-10 04:01:47
【问题描述】:

我创建了一个活动,当单击其中一个文本字段时,它将弹出一个带有产品列表的子项(警报对话框),但是当我单击列表上的一项时,一旦警报已解除。

这是父视图

import Foundation
import UIKit

class ViewAward: UIViewController{

@IBOutlet var tfMCN: UITextField!
@IBOutlet var tfAmount: UITextField!
@IBOutlet var tfProduct: UITextField!
@IBOutlet var tfTotal: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()

    let rightAddBarButtonItem:UIBarButtonItem = UIBarButtonItem(title: "Send", style: UIBarButtonItemStyle.Plain, target: self, action: #selector(ViewAward.searchTapped))

    self.navigationItem.setRightBarButtonItems([rightAddBarButtonItem], animated: true)

    let state = String(ViewPopUpProduct.Product.ProductDescription)
    print("My view state:"+state)

    self.tfProduct.text = state
    tfProduct.addTarget(self, action:  #selector(ViewAward.productTapped), forControlEvents: UIControlEvents.TouchDown)

}

func searchTapped(sender:UIButton) {

    let alertController = UIAlertController(
        title: "Award",
        message:"Award successfully posted!",
        preferredStyle: UIAlertControllerStyle.Alert)
    alertController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default,handler: nil))

    self.presentViewController(alertController, animated: true, completion: nil)
}

func productTapped(textfield: UITextField){

    //tfProduct.endEditing(true)
    tfProduct.resignFirstResponder()

    let popOverVC = UIStoryboard(name:"Main",bundle:nil).instantiateViewControllerWithIdentifier("sbPopUpID") as! ViewPopUpProduct

    self.addChildViewController(popOverVC)

    popOverVC.view.frame = self.view.frame

    self.view.addSubview(popOverVC.view)

    popOverVC.didMoveToParentViewController(self)

}
}

当用户点击项目时

import UIKit

class ViewPopUpProduct: UIViewController {

@IBOutlet var tableView: UITableView!

var productDescription = ["Product 1","Product 2","Product 3"]
var productID = ["prdct1","prdct2","prdct3"]


// Global Variables 
struct Product {
    static var ProductID = String()
    static var ProductDescription = String()
}

override func viewDidLoad() {
    super.viewDidLoad()
    self.showAnimate()
    self.view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.4)

    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

@IBAction func cancelPopUp(sender: AnyObject) {
    self.removeAnimate()
}


func showAnimate()
{
    self.view.transform = CGAffineTransformMakeScale(1.3, 1.3)
    self.view.alpha = 0.0;
    UIView.animateWithDuration(0.25, animations: {
        self.view.alpha = 1.0
        self.view.transform = CGAffineTransformMakeScale(1.0, 1.0)
    });
}

func removeAnimate()
{
    UIView.animateWithDuration(0.25, animations: {
        self.view.transform = CGAffineTransformMakeScale(1.3, 1.3)
        self.view.alpha = 0.0;
        }, completion:{(finished : Bool)  in
            if (finished)
            {
                self.view.removeFromSuperview()
            }
    });
}

//Mark - Table View

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.productID.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("cell",forIndexPath: indexPath) as! ProductViewCell

    cell.productLabel.text = productDescription[indexPath.row]

    return cell
}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    tableView.deselectRowAtIndexPath(indexPath, animated: true)

    Product.ProductID = String(productID[indexPath.row])
    Product.ProductDescription = String(productDescription[indexPath.row])

    self.removeAnimate()

}

}

【问题讨论】:

  • 你能添加你的代码和你显示的警报类型吗?
  • 尝试使用您已实现的一些代码更新您的问题,这将使我们正确了解您在做什么。在此基础上会建议您最好的答案。
  • unexpectedNil 我已经更新了问题
  • 最简单的方法:当你要展示子控制器时,传递一个对self的引用或者一个闭包作为回调。
  • vadian 我使用自我介绍孩子,但当孩子被解雇时我无法更新文本字段的值

标签: ios swift xcode childviewcontroller childviews


【解决方案1】:
  1. 我的首选必须是更快更完美的自定义委托。 (如果您可以使用闭包作为回调,那么这也是一个不错的选择。选择委托来稍微解释一下您的代码。)

  2. 请尽量避免使用 NSNotificationCenter,因为使用它时需要处理很多事情,而且它比委托慢一点。你也可能很容易遇到错误。

现在这是我的代码。

1.子 ViewController 设置。

   //  TrendingProductPageViewController.swift
   //  buddyiOSApp
   //
   //  Created by Tuhin Samui on 5/21/16.
   //  Copyright © 2016 Buddy. All rights reserved.
   //

    import UIKit

    protocol TrendingProductsCustomDelegate: class { //Setting up a Custom delegate for this class. I am using `class` here to make it weak.
        func sendDataBackToHomePageViewController(categoryToRefresh: String?) //This function will send the data back to origin viewcontroller.
    }


    class TrendingProductPageViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, NetworkReachabilityDelegate {

        @IBOutlet weak var productListTableView: UITableView! //Having a tableview outlet here from storyboard itself. BTW not going to explain with tableView delegate and datasource, Sorry..:(

        weak var customDelegateForDataReturn: TrendingProductsCustomDelegate? //Please use weak reference for this to manage the memory issue.


func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
            let rowNumberFromTable: Int = indexPath.row //Getting the index of the selected cell.
            let dataToSendBack = moreMenuTableData[rowNumberFromTable] as! String //This is an array which contains the data for the tableview. Getting the exact data which is selected on the table.
            customDelegateForDataReturn?.sendDataBackToHomePageViewController?(dataToSendBack) //Now sending the selected data back to parent viewController using the custom delegate which I made before.                 presentingViewController?.dismissViewControllerAnimated(true, completion: nil) //Dismissing the viewController here.
    }

2。父 ViewController 代码在这里。

class HomePageViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, TrendingProductsCustomDelegate, UINavigationControllerDelegate{ //Adding the protocol here as `TrendingProductsCustomDelegate`

@IBAction func topTrendingProductsBtnAction(sender: UIButton) { //Normal IBAction of UIButton as you are using.
        let trendingProductsPageForAnimation = storyboard!.instantiateViewControllerWithIdentifier("showTrendingProductpage") as! TrendingProductPageViewController //You can understand this right. Same as yours.
        trendingProductsPageForAnimation.customDelegateForDataReturn = self //Setting up the custom delegate for this class which I have written on the presenting class.
        trendingProductsPageForAnimation.modalPresentationStyle = UIModalPresentationStyle.FullScreen
        presentViewController(trendingProductsPageForAnimation, animated: true, completion: nil) //Same as yours.
    }


func sendDataBackToHomePageViewController(categoryToRefresh: String?) { //Custom delegate function which was defined inside child class to get the data and do the other stuffs.
        if categoryToRefresh != nil {
            print("Got the data is \(categoryToRefresh)")
        }
    }

}

希望这会有所帮助。如有错误请见谅。

【讨论】:

  • 您好,我使用了相同的方法,但是当从 childViewController 调用时,customDelegate 返回 NIL。我有什么遗漏的吗?
  • @Arjun 你确定你传递了正确的值吗?您是否正确地符合委托?如果您认为所有这些都是正确的,那么您可以分享您到目前为止所做的代码,以便我可以调查它。谢谢!
【解决方案2】:

在 ChildVC(ViewPopUpProduct) 中添加 ParentVC 的实例

class ViewPopUpProduct: UIViewController {
  var parentVC = ViewAward? //ParentView
  var someValueToSend : String? 
  .
  .
  .
  fun sendData(){
    // After fetching some value call this function from child
    parentVC.result = someValueToSend
    self.view.removeFromSuperview()
  }
}

在父视图中调用子视图时共享实例

class ViewAward: UIViewController{

   var result = String?//Variable to store result from child

   func productTapped(textfield: UITextField){

    //tfProduct.endEditing(true)
    tfProduct.resignFirstResponder()

    let popOverVC = UIStoryboard(name:"Main",bundle:nil).instantiateViewControllerWithIdentifier("sbPopUpID") as! ViewPopUpProduct

    popOverVC.parentVC = self//Sharing Parent Views Instance

    self.addChildViewController(popOverVC)

    popOverVC.view.frame = self.view.frame

    self.view.addSubview(popOverVC.view)

    popOverVC.didMoveToParentViewController(self)
 }
}

现在移除子视图后 访问 Result 变量并享受吧!

【讨论】:

    【解决方案3】:

    有几种方法可以实现回调功能来传递数据。

    • 委托
    • 使用块回调
    • 发布通知

    但我建议使用委托,这是最好的方式,发布通知也是一种方式,但我不想更喜欢。

    【讨论】:

    • 你能帮我写代码吗?我已经分配了一个全局变量,但是当视图重新加载时它会更新文本字段值,而不是当孩子被解雇时
    【解决方案4】:

    你可以使用协议/委托

    这是一个非常非常直接的解释,没有bs: https://www.youtube.com/watch?v=guSYMPaXLaw

    或者在你的情况下你也可以使用 NSNotificationCenter

    你可以这样做:

    “发送者”视图控制器会这样做

    let nc = NSNotificationCenter.defaultCenter()
    nc.postNotificationName("printValue", object: nil, userInfo: ["value" : "Pass Me this string"])
    

    接收者视图控制器然后可以收听通知。

    let nc = NSNotificationCenter.defaultCenter()
    nc.addObserver(self, selector: #selector(printValue), name: "printValue", object: nil)
    
    func printValue(notification:NSNotification) {
        let userInfo:Dictionary<String,String> = notification.userInfo as! Dictionary<String,String>
        let item = userInfo["value"]! as String
    
        print(item,self)
    }
    

    【讨论】:

    • 谢谢,但我的问题是我没有使用 segue 我加载了一个子视图,并且在那个子视图中有项目表,当我单击项目时,我将抓取选定的项目并解雇子视图并在文本字段上显示抓取的数据
    • NSNotification 是相关视图控制器最糟糕和最昂贵的方式。协议/委托要好得多(作为回​​调的闭包是最先进的)。
    • @vadian 然后给我们您的解决方案:|
    【解决方案5】:

    我通常为此使用闭包。比委托更简单、更简洁:

    class MainViewController: UIViewController {
    
        func showChildViewController() {
            guard let vc = storyboard?.instantiateViewControllerWithIdentifier("ChildViewController") as? ChildViewController else {
                return
            }
            vc.didSelectItem = { [weak self](item) in
                if let vc = self {
                    // Do something with the item.
                }
            }
            presentViewController(vc, animated: true, completion: nil)
        }
    
    }
    
    class ChildViewController: UIViewController {
    
        var didSelectItem: ((item: Item) -> Void)?
    
        @IBAction func buttonPressed() {
            didSelectItem?(item: <#your item goes here#>)
        }
    
    }
    

    【讨论】:

    • 我用它来显示子 'code' func productTapped(textfield: UITextField){ //tfProduct.endEditing(true) tfProduct.resignFirstResponder() let popOverVC = UIStoryboard(name:"Main", bundle:nil).instantiateViewControllerWithIdentifier("sbPopUpID") as! ViewPopUpProduct self.addChildViewController(popOverVC) popOverVC.view.frame = self.view.frame self.view.addSubview(popOverVC.view) popOverVC.didMoveToParentViewController(self) } 'code'
    • @JosephVincentMagtalas 我给了你一个大致的想法如何实现这一点。请根据您的需要自行调整我的回答。
    • 物品来自哪里?在` var didSelectItem: ((item: Item) -> Void)? ` 我是开发应用程序的新手,谢谢
    • @JosephVincentMagtalas 查看buttonPressed 方法。在那里你用适当的参数调用闭包
    猜你喜欢
    • 1970-01-01
    • 2020-04-01
    • 2018-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多