My question is duplicate but I need not a suitable answer. Also, I have raised the same before how to callback the array of data to another viewController in iOS Swift
I have a parent viewController called CreateCardViewController and a child controller called webViewController.
In parent viewController, I have used carbonKit for showing the tab bar menu. When the tab bar menu first index is webViewController (that's a child controller).
My question is: How to send data to the parent controller from the child controller?
For example: From a child, viewController will get a list of tab bar menu items. After getting tab bar menu items, I need to send menu items to parent viewController to show tab bar.
Here is the clear picture, which I am trying to do:
you can use delegate like what #Aqua said. or use observation for this.
class ParentViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.updateParentViewController(_:)), name: Notification.Name(rawValue: "updateParentViewController"), object: nil)
}
#IBaction func updateParentViewController(_ notification: NSNotification){
if let receivedData = notification.userInfo?["data"] as? Any {
//use received data
// update your parentViewController.
}
}
}
//.............
class ChildViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
func sendDataToParentViewController() {
let dataDict:[String: Any] = ["data"://what you want to send.]
NotificationCenter.default.post(name: . updateParentViewController, object: nil, userInfo: dataDict)
}
}
this works for me.
On your custom ChildViewController add propertyparentViewController and set it when you create that child view controller. Then, implement specific method on parent viewcontroller, that receives data from child view controller.
protocol ParentViewControllerProtocol {
func receiveChildData(_ child: UIViewController, data: Any)
}
class ChildViewController: UIViewController {
var parentViewController: ParentViewControllerProtocol!
func timeToSendDataToParentViewController() {
parentViewController.receiveChildData(self, data: self.data)
}
}
class ParentViewController: UIViewController, ParentViewControllerProtocol {
func receiveChildData(_ child: UIViewController, data: Any) {/*handle data*/}
func addChildViewController() {
let child = ChildViewController();
child.parentViewController = self
// do the rest of adding child to parent
}
}
Related
I want to pass my data from child view controller to parent view controller.
I'm just moving the child view to the top of the parent view, here is my code:
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let toChildView = storyBoard.instantiateViewController(identifier: "toChildView")
// show child view
self.addChild(toChildView)
toChildView.willMove(toParent: self)
toChildView.view.frame = self.view.bounds
self.view.addSubview(toChildView.view)
toChildView.didMove(toParent: self)
Here is the delegate:
protocol DataDelegate {
func printTextField(string: String)
}
I added variable delegate to my Child View
var delegate: DataDelegate?
And send the data to Parent View
#IBAction func btnSend(_ sender: Any) {
delegate?.printTextField(string: textField.text)
}
And close the Child View, like:
#IBAction func btnClose(_ sender: Any) {
// back to parent view
self.willMove(toParent: nil)
self.view.removeFromSuperview()
self.removeFromParent()
}
Calling the DataDelegate to Parent View
class ParentView: UIViewController, DataDelegate {
func printTextField(string: String) {
print(string)
}
}
Im planning to pass the data of my text field from child view to parent view, I try this codes:
https://jamesrochabrun.medium.com/implementing-delegates-in-swift-step-by-step-d3211cbac3ef
https://www.youtube.com/watch?v=aAmvQU9HccA&t=438s
but it didn't work, any help thanks :)
EDITED: Added my delegate implementation code...
So as per the code you have done with declaration but not initialized the delegate. So go to you ParentView and assign the delegate in viewDidLoad or in the function where you prepare to move on child like:-
toChildView.delegate = self
And try again. :-)
you will not get delegate property in parent view as it is member of childView. You can do following
self.addChild(toChildView)
toChildView.delegate = self
I am having a problem accessing my UIButton that's inside a ContainerView from another ViewController.
If the user taps the button a SubView should appear inside of my ViewController. I tried dragging the button in my ViewController file to create an #IBAaction func tapped() but that is not working.
It only works inside of the ContainerView.swift file. But I can not create my Subview there...
I hope you get my problem, I am grateful for every help!
import UIKit
class ContainerViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func addButtonTapped(_ sender: Any) {
print("add Button")
}
You can reach your ViewController inside your ContainerView using its parent property. So, inside your ContainerView class:
if let parentVC = self.parent as? ViewController {
parentVC.showSubView() // your method to show the sub view.
}
You can achieve this using NotificationCenter and Delegates. Here is how you can achieve it with NotificationCenter
In your ContainerViewController you can post notification on button click
#IBAction func yourBtnTap(sender : UIButton) {
NotificationCenter.default.post(name: Notification.Name("myBtnTapped"), object: nil)
}
In your CurrentViewController you have to first register to receive this notification. So in your viewDidLoad, do this:
NotificationCenter.default.addObserver(self, selector: #selector(self.myBtnTappedAction(notification:)), name: Notification.Name("myBtnTapped"), object: nil)
Now in your CurrentViewContoller create myBtnTappedAction function that will be called whenever the button is tapped.
#objc func myBtnTappedAction(notification : Notification) {
// now you can perform all your actions here. this function will be called everytime the button in the container view is tapped.
}
In my project I have UINavigationController with three embedded UIViewControllers. On the first one I add balanceLabel and refreshButton to navigation bar. When click on button first view controller send url request and show return value on label.
#IBAction func refreshButtonAction(_ sender: UIBarButtonItem) {
let operation = GetInfoOperation(...)
operation.completionBlock = { [weak self] in
DispatchQueue.main.async {
guard let balance = operation.output?.value?.balance else { return }
self?.balanceLabel.text = balance
let significantDigits = Int(Double(balance.toInt64!) * pow(10, -10))
}
}
queue.addOperation(operation)
}
How can I get the same behaviour on other ViewControllers without duplicate #IBAction func refreshButtonAction(_ sender: UIBarButtonItem) in each ViewController?
you can archive this by extension, using inheritance,
create the view controller you want with all the common feature you want and then instead of inheriting directly from UIViewController inherit from that base viewController
your base controller BaseViewController
class BaseViewController: UIViewController {
//all comman functionallity
//add your button here
}
class ChildOneViewController: BaseViewController {
//this class will get all the functionality from BaseViewController
//you can access the BaseViewController button here
//add function for ChildOneViewController
}
class ChildtwoViewController: BaseViewController {
//this class will get all the functionality from BaseViewController
//you can access the BaseViewController button here
//add function for ChildtwoViewController
}
I have UITabBarController. From the Home tab, I segued to a ThankYouVC.
When I unwind from ThankYouVC, I want to change the selected tab.
What I've tried:
HomeVC
#IBAction func unwindToMain(segue:UIStoryboardSegue) {
print("unwind")
self.tabBarController?.selectedIndex = 0
}
The console log prints unwind, but doesn't change the index.
Another attempt:
enum Notifications: String, NotificationName {
case QRDoneNotification
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(unwindCallBack), name: Notification.Name("QRDoneNotification"), object: nil)
}
#IBAction func unwindToMain(segue:UIStoryboardSegue) {
print("unwind")
NotificationCenter.default.post(name: Notifications.QRDoneNotification.name, object: nil)
}
func unwindCallBack() {
self.tabBarController?.selectedIndex = 0
}
Still no luck!!
Help me out.
The problem is that an unwind segue unwinds to the view controller that holds the function. So that's where you end up.
One solution: subclass UITabBarController and put your unwind segue there.
class MyTabBarController: UITabBarController {
#IBAction func unwindToMain(segue:UIStoryboardSegue) {
print("Unwinding to the custom tab bar controller...")
selectedIndex = 1
}
}
So, add that class to your project... set the Custom Class of your current UITabBarController to MyTabBarController... Assign your Exit / Unwind segue to this new one, and don't forget to delete your existing unwindToMain() function and unwind connection.
I have an reference to a managed object called selectedItem, I load the data in on view controller and have a modal segue (over current context) to another view to edit the title property of the selectedItem.
I expect a textLabel to refresh the data when dismissing the modal view but it does not. I have used the same method to add to the table data and it worked, because I use tableView.reloadData but how can I refresh the label data using the modal segue ? or basically have the label change to the new value.
detailsViewController
var selectedItem: Item!
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
self.tableView.reloadData()
titleLabel.text = selectedItem.title
}
override func viewDidLoad() {
super.viewDidLoad()
titleLabel.text = selectedItem.title
}
EditViewController
#IBAction func save(sender: AnyObject) {
selectedItem.title = editTitle.text
var error: NSError?
if context!.save(nil){}
context?.save(&error)
self.presentingViewController?.viewWillAppear(true)
self.dismissViewControllerAnimated(true, completion: {});
}
PS: I tried to do a work around by using another segue to go back to the first view but that crashed, does anybody know why ?
You can use a NSNotification, they are pretty handy for this sort of thing, here's an example of some generic usage:
Parent View Controller
In viewDidLoad:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "udpateObject:", name: "udpateObject", object: nil)
In deinit:
NSNotificationCenter.defaultCenter().removeObserver(self, name: "udpateObject", object: nil)
Then you'll make a func that matches the selector of the observer:
func udpateObject(notification: NSNotification) {
// here you'll get the object you update in a different view
if let receivedObject = notification.object as? YOUR_OBJECT_DATA_TYPE {
self.ThisInstanceVariable = receivedObject
// Update any UI elements
}
}
Update View Controller
Wherever you update your data:
NSNotificationCenter.defaultCenter().postNotificationName("udpateObject", object: YOUR_UPDATED_OBJECT)