如何从子视图控制器传递数据到父视图控制器?在斯威夫特



我创建了一个活动,当其中一个文本字段被点击时,它会弹出一个带有产品列表的子(警报对话框),但是当我点击列表中的一个项目时,我无法在文本文件中显示它,一旦警报被解除。

这是父视图

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()
}
}

我通常使用闭包来达到这个目的。比委托更简单,更简洁:

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#>)
    }
}

你可以使用protocols/delegate

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

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

你可以这样做:

sender视图控制器会做

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)
}

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

  • Using Block CallBack
  • 事后通知

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

  1. 我的第一偏好必须是自定义代表,这是更快和完美的。(如果您可以使用闭包作为回调,那么这也是一个不错的选择。选择委托来解释使用你的代码)

  2. 请尽量避免使用NSNotificationCenter,因为当你使用它的时候有很多事情需要处理,而且它比委托慢一点。

现在这是我的代码。

1。子视图控制器设置。

   //  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。

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)")
        }
    }
}

希望这有帮助。

在childdvc (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)
 }
}

现在删除子视图后访问结果变量并享受吧!

最新更新