I have a basic understanding of how to handle swift protocols to pass data between two viewcontrollers. My situation is this: I wanted to pass data back to my first viewcontroller.
For example:
First ViewController
class ViewControllerA: UIViewController, ViewControllerCResult {
func set(data: String) {
}
}
Second ViewController
class ViewControllerB: UIViewController {
}
Third ViewController
protocol ViewControllerCResult {
set(data: String)
}
class ViewControllerC: UIViewController {
var delegate: ViewControllerCResult?
}
ViewControllerA -> ViewControllerB -> ViewControllerC
I would like to pass data from ViewControllerC to ViewControllerA.
Can anyone help me with this?
You can pass Delegates from Controller A -> B -> C , and when popViewcontroller will be called you can check the self.delegate in ViewController C, if it exist just call function like this self.delegate?.set("data from c"). Check
popControllerPressed Function in ViewController3
First View controller
class ViewController: UIViewController, ViewControllerCResult {
var delegate: ViewControllerCResult?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func pushControllerPressed(_ sender: Any) {
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController2") as? ViewController2 {
if let navigator = navigationController {
viewController.delegate = self
navigator.pushViewController(viewController, animated: true)
}
}
}
func set(data: String) {
}
}
Second ViewController
class ViewController2: UIViewController, ViewControllerCResult {
var delegate: ViewControllerCResult?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func pushControllerPressed(_ sender: Any) {
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController3") as? ViewController3 {
if let navigator = navigationController {
viewController.delegate = self.delegate
navigator.pushViewController(viewController, animated: true)
}
}
}
func set(data: String) {
print(data)
}
}
Third ViewController
protocol ViewControllerCResult {
func set(data: String)
}
class ViewController3: UIViewController, ViewControllerCResult {
var delegate: ViewControllerCResult?
func set(data: String) {
print(data)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func popControllerPressed(_ sender: Any) {
for controller in self.navigationController!.viewControllers as Array {
if controller.isKind(of: ViewController.self) {
delegate?.set(data: "data from C")
self.navigationController!.popToViewController(controller, animated: true)
break
}
}
}
}
Here is Code Link: Pass data forth and back
Related
I have 2 VC's, and one navigation controller between them. How can i set First screen as a delegate of Second?
What i tried:
Present SecondVC from frist (it presents it without navigation)
Setting delegate in NavVC viewDidLoad()
FirstVC:
class MainVC: UIViewController, SecondVCDelegate {
func passData(text: String) {
// do stuff
}
#IBAction func openNextVC(_ sender: Any) {
let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NavVC") as! NavVC
present(nextVC, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Navigation Controller:
class NavVC: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
SecondVC:
protocol SecondVCDelegate {
func passData(text: String)
}
class SecondVC: UIViewController {
var delegate: SecondVCDelegate?
#IBAction func save(_ sender: Any) {
// do stuff
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Main task here would be to access second view controller instance from navigation controller instance(navC). And to achieve this, you have to first access the rootViewController from your navigation controller instance(nextVC) as below:
let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NavVC") as! NavVC
let secondVC = nextVC?.viewControllers.first as? SecondVC
secondVC.delegate = self
present(nextVC, animated: true, completion: nil)
The above code is applicable when second view controller is the root of your navigation controller. If second view controller is not the root controller to navC, then you have to iterate the controllers to get second view controller instance. Once second controller instance is there, then you can assign the delegate to the same as below.
for controller in navC.viewControllers {
if controller.isKind(of: SecondVC.self) {
if let secondVc = controller as? SecondVC {
secondVc.delegate = self
}
break
}
}
I handled the same thing. Try this on MainVC:
class MainVC: UIViewController, SecondVCDelegate {
func passData(text: String) {
// do stuff
}
#IBAction func openNextVC(_ sender: Any) {
guard let secondController = self.storyboard?.instantiateViewController(withIdentifier: "AddGroupVC") as? AddGroupVC else { return }
secondController.delegate = { [weak self] in
print("call your delegates here")
}
self.navigationController?.present(secondController, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
On second View Controller, call the delegates in viewWillDisappear :
class SecondVC: UIViewController {
var delegate: SecondVCDelegate?
#IBAction func save(_ sender: Any) {
// do stuff
self.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillDisappear(_ animated: Bool) {
self.delegate
}
}
My protocol (where "VehicleRegVCs" is enum):
protocol VehicleRegVCDelegate: class {
func presentedVC(_ currentVC: VehicleRegVCs)
}
My Buyer Class:
class BuyerOwnerInfoViewController: UIViewController {
weak var delegate: VehicleRegVCDelegate?
override func viewDidLoad() {
super.viewDidLoad()
delegate?.presentedVC(.buyerOwnerInfo)
}
}
My Main class (where delegate function "func presentedVC" at the bottom not getting called):
class VehicleRegContainerViewController: ICTViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
func setupView() {
let buyerVC = getBuyerOwnerInfoVC()
buyerVC.delegate = self
}
}
extension VehicleRegContainerViewController: VehicleRegVCDelegate {
func presentedVC(_ currentVC: VehicleRegVCs) {
}
}
I expect "presentedVC" to get called... I made a delegate too...
and in UIViewController extension i have made this function...
func getBuyerOwnerInfoVC() -> BuyerOwnerInfoViewController {
let vc = UIStoryboard.exciseAndTaxation.instantiateViewController(withIdentifier: "BuyerOwnerInfoViewController") as! BuyerOwnerInfoViewController
return vc
}
ViewController inside containerView are connected using segue. You can use prepareForSegue method to get the controller and assign the delegate to it.
NOTE: Go to storyboard and click on the segue connecting the container view and the view controller, and assign it an identifier. In below example i have used "yourSegueIdentifier", replace it with your identifier.
class VehicleRegContainerViewController: ICTViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let buyerVC = segue.destination as? BuyerOwnerInfoViewController {
buyerVC.delegate = self
} else {
print("Error in segue")
}
}
}
enter image description herei am making a program with delegate protocol in which we add value in text field in second controller and click save and this value is set to the label in the previous viewController
all the this are done but the value can not set to the label
Can someone please explain me what is triggering the messageData() method in the main ViewController?
import UIKit
protocol SenderViewControllerDelegate {
func messageData(data: String)
}
class NewViewController: UIViewController {
//MARK:- Properties
#IBOutlet weak var firstTextField: UITextField!
var delegate: SenderViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func SaveFirstValue(_ sender: Any) {
if delegate != nil{
if firstTextField.text != nil{
let data = firstTextField.text
delegate?.messageData(data: data!)
dismiss(animated: true, completion: nil)
}
}
}
}
import UIKit
class ViewController: UIViewController,SenderViewControllerDelegate {
//MARK:- Properties
#IBOutlet var firstLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK:- Actions
func messageData(data: String) {
firstLabel.text = data
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showSendingVc" {
let viewController : ViewController = segue.destination as! NewViewController
ViewController.delegate = self
}
}
}
Change this line
let viewController = segue.destination as! NewViewController
viewController.delegate = self
`ViewController.delegate = self` should be `viewController.delegate = self`
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showSendingVc" {
let viewController : NewViewController = segue.destination as! NewViewController //destination is type NewViewController not ViewController
// ViewController.delegate = self //Wrong
viewController.delegate = self
}
}
You made mistake in the line ViewController.delegate = self it should be
viewController.delegate = self
means small "v" (object of ViewController)
UPDATED:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showSendingVc" {
let objectOfVC = segue.destination as! NewViewController
objectOfVC.delegate = self
}
}
In ViewController Class set the delegate inside ViewDidLoad method like this:
newViewControllerObj. delegate = self
Without calling viewController Class, the delegate will not set So you have to call ViewController class inside NewViewController or other class which will call first like that:
let ViewControllerObj = ViewController()
I am trying to change lable of one view controller from another view controller using custom protocol but its delegate method is not being called
ViewController3 code:
when i click on close button it's delegate method is not being called in my ViewController2.
protocol ViewController3Delegate: class {
func changeLable(_ text: String)
}
class ViewController3: UIViewController {
weak var delegate: ViewController3Delegate?
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func btnCloseAction(_ sender: Any) {
delegate?.changeLable("fillter applied")
self.dismiss(animated: true, completion: nil)
}
}
ViewController2 code:
class ViewController2: UIViewController,ViewController3Delegate {
#IBOutlet weak var lblReport: UILabel!
let VC3 = ViewController3(nibName: "ViewController3", bundle: nil)
override func viewDidLoad() {
super.viewDidLoad()
VC3.delegate = self
}
func changeLable(_ text: String) {
print("delegate called")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Anybody knows where i am wrong, please suggest me some solution
You have not defined a delegate in your ViewController2 which will be used to the delegate in ViewController3 .
See This :
protocol ViewController3Delegate: class {
func changeLable(_ text: String)
}
class ViewController3: UIViewController {
weak var delegate: ViewController3Delegate?
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func btnCloseAction(_ sender: Any) {
if delgate !=nil {
delegate?.changeLable("fillter applied")
self.dismiss(animated: true, completion: nil)
}
}
}
And then in your ViewController2 class :
class ViewController2: UIViewController,ViewController3Delegate {
#IBOutlet weak var lblReport: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func changeLable(_ text: String) {
print("delegate called")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier = "Yoursegueientifier"
{
let vc = segue.destination as! ViewController3
vc.delegate = self
}
}
}
Note : You have to define your segueidentifer name in your storyboard
You should first present ViewController3 from ViewController2 like this:
let VC3 = ViewController3(nibName: "ViewController3", bundle: nil)
VC3.delegate = self
self.presentViewController(VC3, animated: true, completion: nil)
Also, you can delete this line above viewDidLoad
let VC3 = ViewController3(nibName: "ViewController3", bundle: nil)
I have attached the sample code that illustrates the issue I'm having. For some reason a tableview needs to be the first tab in order for the tableviewcontroller recognize the navbar. This question is an extension on this question I asked yesterday
Here's a link to the actual sample project iosTableTabTest
AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
let containerViewController:ContainerViewController = ContainerViewController()
window!.rootViewController = containerViewController
window!.makeKeyAndVisible()
return true
}
ContainerViewController.swift:
class ContainerViewController: UIViewController, LoginDelegate {
var mainNavigationController: UINavigationController!
var myTabBarController: UITabBarController!
var loginViewController: LoginViewController!
override func viewDidLoad() {
super.viewDidLoad()
var mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
myTabBarController = mainStoryboard.instantiateViewControllerWithIdentifier("myTabBarController") as? UITabBarController
loginViewController = mainStoryboard.instantiateViewControllerWithIdentifier("loginViewController") as? LoginViewController
loginViewController.delegate = self
mainNavigationController = UINavigationController(rootViewController: loginViewController)
view.addSubview(mainNavigationController.view)
addChildViewController(mainNavigationController)
mainNavigationController.didMoveToParentViewController(self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func loginPressed() {
self.mainNavigationController.pushViewController(self.myTabBarController, animated: false)
}
}
LoginViewController.swift:
#objc
protocol LoginDelegate{
func loginPressed()
}
class LoginViewController: UIViewController {
#IBOutlet var loginBtn: UIButton!
var delegate: LoginDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func loginPressed(sender: AnyObject) {
delegate?.loginPressed()
}
}
FirstTabViewController.swift:
class FirstTabViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.topViewController.navigationItem.setHidesBackButton(true, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
SecondTabViewController.swift:
class SecondTabViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
I read through your code and ran your project, and I believe the issue lies in that you're embedding the UITabBarController in a UINavigationController. What you want to do is have each UIViewController (or UITableViewController) embedded in its own UINavigationController, then set these navigation controllers as the UITabBarController's view controllers (ie. you can set this up on the storyboard).
That's why there's also an issue with the content inset of the tableviewcontroller on your second tab (the first row hidden under the navigation bar). The UINavigationController in which the UITabBarController is embedded doesn't pass the proper insets through the UITabBarController to its view controllers.
I made some changes to your project: TableTest
Main.storyboard
I embedded each of the UITabBarController's view controllers in its own UINavigationController
ContainerViewController
I added the views of the loginViewController and myTabBarController as subviews of the container VC's view, then added each controller as child controllers of the container VC. You can still embed the loginViewController in a UINavigationController if you to have the navigation bar, but I removed it for simplicity.
class ContainerViewController: UIViewController, LoginDelegate {
//var mainNavigationController: UINavigationController!
var myTabBarController: UITabBarController!
var loginViewController: LoginViewController!
override func viewDidLoad() {
super.viewDidLoad()
var mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
myTabBarController = mainStoryboard.instantiateViewControllerWithIdentifier("myTabBarController") as? UITabBarController
loginViewController = mainStoryboard.instantiateViewControllerWithIdentifier("loginViewController") as? LoginViewController
loginViewController.delegate = self
//mainNavigationController = UINavigationController(rootViewController: loginViewController)
//view.addSubview(mainNavigationController.view)
//addChildViewController(mainNavigationController)
//mainNavigationController.didMoveToParentViewController(self)
view.addSubview(myTabBarController.view)
view.addSubview(loginViewController.view)
self.addChildViewController(myTabBarController)
self.addChildViewController(loginViewController)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func loginPressed() {
//self.mainNavigationController.pushViewController(self.myTabBarController, animated: false)
loginViewController.view.removeFromSuperview()
loginViewController.removeFromParentViewController()
}
}
FirstTabViewController
Since this view controller is embedded now in its own UINavigationController in the storyboard, it can access its navigationItem just as self.navigationItem
class FirstTabViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//self.navigationController?.topViewController.navigationItem.setHidesBackButton(true, animated: true)
self.navigationItem.setHidesBackButton(true, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}