如何将数据从子视图控制器传递到父视图控制器?在 swift
How to pass data from child to parent view controller? in swift
我创建了一个 activity,当点击其中一个文本字段时,它会弹出一个带有产品列表的子项(警告对话框),但是当我点击列表中的一个项目时,我无法显示它在警报解除后提交的文本上。
这是父视图
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()
}
}
实现回调功能以传递数据的方法很少。
- 代表
- 使用块回调
- Post通知
但我建议使用委托,这是最好的方式,Post通知也是一种方式,但我不想偏爱。
您可以使用protocols/delegate
这是一个非常非常直接的解释,没有废话:
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)
}
我通常为此目的使用闭包。比委托更简单、更简洁:
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#>)
}
}
我的首选肯定是 Custom Delegate,它更快更完美。 (如果您可以使用闭包作为回调,那么这也是一个不错的选择。选择委托来稍微解释一下您的代码。)
请尽可能避免使用 NSNotificationCenter,因为使用它时需要处理的事情太多,而且它比代理慢一点。您也可能很容易遇到错误。
现在这是我的代码。
1. Child 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。 Parent 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)")
}
}
}
希望这对您有所帮助。如有任何错误,请见谅。
在 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)
}
}
删除子视图后
访问结果变量并享受!
我创建了一个 activity,当点击其中一个文本字段时,它会弹出一个带有产品列表的子项(警告对话框),但是当我点击列表中的一个项目时,我无法显示它在警报解除后提交的文本上。
这是父视图
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()
}
}
实现回调功能以传递数据的方法很少。
- 代表
- 使用块回调
- Post通知
但我建议使用委托,这是最好的方式,Post通知也是一种方式,但我不想偏爱。
您可以使用protocols/delegate
这是一个非常非常直接的解释,没有废话: 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)
}
我通常为此目的使用闭包。比委托更简单、更简洁:
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#>)
}
}
我的首选肯定是 Custom Delegate,它更快更完美。 (如果您可以使用闭包作为回调,那么这也是一个不错的选择。选择委托来稍微解释一下您的代码。)
请尽可能避免使用 NSNotificationCenter,因为使用它时需要处理的事情太多,而且它比代理慢一点。您也可能很容易遇到错误。
现在这是我的代码。
1. Child 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。 Parent 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)")
}
}
}
希望这对您有所帮助。如有任何错误,请见谅。
在 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)
}
}
删除子视图后 访问结果变量并享受!