I have 5 instances of CalculatorViewController in my storyboard, but only one with identifier "secondOperationViewController". 3 of them connected with my initial ViewController named ContainerViewController using embed segues.
I want ViewController with identifier "secondOperationViewController" to call method from my ContainerViewController, but I cant correctly instantiate it, so delegate method not being called. Here is part of my code:
override func viewDidLoad() {
super.viewDidLoad()
secondOperationViewController = storyboard.instantiateViewControllerWithIdentifier("secondOperationViewController") as? CalculatorViewController
secondOperationViewController!.delegate = self
println(secondOperationViewController)
}
Any suggestions what's wrong here?
Also I found similar question:
Delegate in Swift-language
I rewrited instantion of my CalculatorViewController to:
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
secondOperationViewController = segue!.destinationViewController as? CalculatorViewController
secondOperationViewController!.delegate = self;
}
It works, but my delegate method is being called from all 3 ViewControllers, connected to initial ViewController, so I need another solution.
So how can I call delegate method exactly from ViewController with specified identifier? Any ideas?
So, embed segue doesn't work with "instantiateViewControllerWithIdentifier" (but works with modal presented segue). I dont know why. Here is solution for embed segue:
override func viewDidLoad() {
super.viewDidLoad()
let secondOperationViewController:CalculatorViewController = childViewControllers[0] as CalculatorViewController
secondOperationViewController.delegate = self
}
In the storyboard give your segue a unique identifier:
Then in your prepareForSegue check against that before you set the delegate, this way you know exactly when you will be setting up this delegate.
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
// Checking to make sure this is the correct segue. This is also protection for the "as?"
if segue?.identifier == "SecondOVCSeuge" {
secondOperationViewController = segue!.destinationViewController as? CalculatorViewController
secondOperationViewController!.delegate = self;
}
}
Related
I'm trying to send data from one ViewController to another with delegate, but can't seem to get the right instance
I've tried setting the delegate at different places within the receiving ViewController including ViewDidLoad, but the delegate in the sending ViewController is always nil.
From what I've learned, it's an average problem everybody seems to go through, and I've read quite a number of samples, tried them, but to no avail. I don't know if I'm leaving something out or not. Please shed some light if you will.
Below is what I ended up with.
The sending ViewController:
protocol CreateChatDelegate: class{
func appendChatData(_ sender: CreateChatViewController)
}
class CreateChatViewController: UIViewController {
weak var delegate: CreateChatDelegate!
#IBAction func createChat(_ sender: AnyObject) {
delegate?.appendChatData(self)
if delegate == nil {
print("delegate unsuccessful")
} else {
print("delegate successful")
}
}
The receiving ViewController:
class ViewController: UIViewController{
var createChatViewController: CreateChatViewController!
override func viewDidLoad() {
super.viewDidLoad()
...
}
}
extension ViewController: CreateChatDelegate {
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// get the reference to the ViewController
self.createChatViewController = segue.destination as? CreateChatViewController
// set it as delegate
self.createChatViewController?.delegate = self
print("ViewController: delegate successful")
}
}
func appendChatData(_ sender: CreateChatViewController) {
print("ViewController: CreateChatDelegate called")
}
}
this code outputs "delegate unsuccessful", because delegate is always nil
The method you are using is incorrect. You should use the new one:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
....
}
Notice the override keyword? if you don't see this when you are writing the viewController methods, It means that you are NOT calling the original method and misspelled the function signature.
NOTE: if you are targeting older iOS and using older Xcode, the method name may be different, you should write the name of the method and let the AutoComplete help you with the correct one.
To successsfuly configure segue you need to make sure that
1- Navigation is triggered by
self.performSegue(withIdentifier:"segue",sender:nil)
2- Force-unwrap
self.createChatViewController = segue.destination as! CreateChatViewController
as as? cast may fail silently for some reason
First make sure that prepareForSegue() method is called. Then make sure that it is called for the CreateChatViewController i.e.
if let destination = segue.destination as? CreateChatViewController {
//Do all the stuff there e.g.
destination.delegate = self
}
If your prepareForSegue() method is not called then set the action properly so it will fire the prepareForSegue() method then you will get the delegate value in the CreateChatViewController.
I have gone through all the other posts about this topic but they don't seem to help me.
I have a UITabBarController that is launching two tabs. I want to pass data collected in tab1 to the UITabBar ViewController. I am trying to use delegete protocol for this but I am having trouble setting the delegate variable in the sending ViewController. The prepare for segue never gets called. I cannot even cycle through the viewcontrollers of the tabs inside the ViewDidLoad() of the Tabbar controller as they are not created yet and so nil.
I have used delegates before and it seems rather straightforward. Does it matter that I am using it in a Tabbar?
When I run the code the viewDidLoad() in TabBarViewController is called but not the preparefor segue.
The IBAction donePressed in the MeViewController is called but the delegate is not called as its not set.
Here is the code --
protocol DetailsDelegate: class {
func myDetailsGathered( myDetails: MyDetails )
}
/// RECEIVING VIEW CONTROLLER
class TabBarViewController: UITabBarController, DetailsDelegate
{
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
print("prepare for segue called\n");
if let destinationViewController = segue.destination as? MeViewController
{
destinationViewController.delegate = self
}
}
override func viewDidLoad()
{
print("ViewDidLoad Called \n")
}
func myDetailsGathered(myDetails: MyDetails)
{
self.myDetails = myDetails
print("My details gathered \n")
}
}
---------------
/// SENDING VIEW CONTROLLER
class MeViewController: UIViewController
{
weak var delegate: DetailsDelegate?
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
// I have UIButton in the view and this is invoked when its pressed.
#IBAction func donePressed(_ sender: Any)
{
var infoToPass = MyDetails()
print("looks like we are done")
delegate?.myDetailsGathered(infoToPass: myDetails)
}
}
prepareForSegue is called when you perform a segue. Which you don´t do and that´s why it does not get called.
A segue defines a transition between two view controllers in your
app’s storyboard file.
You should use a singleton class to store variables and access them between different controllers. You declare one like this:
class Singleton {
static let sharedInstance = Singleton()
var name = ""
}
Assign to Singleton:
Singleton.sharedInstance.name = "Some name"
To read from it from whatever controller:
let name = Singleton.sharedInstance.name
First of all, why do you want your tabbarController to receive some info/data though?
The prepare for segue never gets called.
prepareForSegue method will be invoked right after the performSegue. So where's your performSegue method? Or are you sure that that kind of segue going to MeViewController is being performed?
One more option you have is to use NotificationCenter.
I am new to xcode 7 and it would be great if you could help me with something.
I have two ViewControllers and I would like to call ViewController2 from ViewController1. I need to do that by code. (I would like to call it from the viewDidLoad()-function)
Thanks in advance
Depending on how you have the project and your navigation setup, here is one of the many ways to accomplish what I think you are asking.
If you are using Segues for navigation, in the ViewController1 (That initialized the navigation) you would override the prepareForSegue function cast your segue.destination as ViewController2 and set the property. Like this
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
guard let viewController2 = segue.destination as? ViewController2 else { return }
viewController2.propertyName = "Property Value"
}
Or, if you are wanting to instantiate ViewController2 in ViewController1 you could do this:
override viewDidLoad() {
super.viewDidLoad()
guard let viewController2 = self.storyboard?.instantiateViewController(withIdentifier: "ID for ViewController (set in the Storyboard)") as? ViewController2 else { return }
viewController2.propertyName = "Property Value"
self.present(viewController2, animated: true, completion: nil)
// Or you could do if you want a full navigation, not just a modal.
self.show(viewController2, sender: self)
}
If you are wanting to access each view controller, you could do something like this:
class ViewController2: UIViewController {
weak var viewController1: ViewController1? //The 'weak' keyword is incredibly important so that you don't have a memory leak.
override viewDidLoad() {
self.viewController1.propertyName = "Property Value"
}
}
Using the same steps as above, you can set the viewController1 property in the ViewController2 instance.
Now I hope that answers your question. Your question is a little vague, so I am shooting in the dark.
I want to segue from a view container within "H" that is presented using the navigation controller connected to the Split View Controller. How can I accomplish this? I have tried regular performSegueWithIdentifier using locally linked storyboard ID's but that removes the top navigation bar. I want to retain the top navigation bar and execute the segue as if it was done using the master navigation controller (rows that select which view controller is being presented in the detail view).
Any help is greatly appreciated!
Here is an example of how to perform a segue from an embedded ViewController.
ViewController.swift
import UIKit
protocol SegueHandler: class {
func segueToNext(identifier: String)
}
class ViewController: UIViewController, SegueHandler {
func segueToNext(identifier: String) {
self.performSegueWithIdentifier(identifier, sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EmbedH" {
let dvc = segue.destinationViewController as! HViewController
dvc.delegate = self
}
}
}
HViewController.swift
import UIKit
class HViewController: UIViewController {
weak var delegate: SegueHandler?
#IBAction func pressH(sender: UIButton) {
delegate?.segueToNext("GoToGreen")
}
}
Setup:
Use delegation to have the HViewController tell its embedding viewController to perform the segue.
Create a protocol called SegueHandler which just describes a class that implements the method segueToNext(identifier: String).
protocol SegueHandler: class {
func segueToNext(identifier: String)
}
Make your viewController implement this protocol by adding it to the class declaration line:
class ViewController: UIViewController, SegueHandler {
and by implementing the required function.
Add a delegate property to HViewController:
weak var delegate: SegueHandler?
Click on the embed segue arrow between ViewController and HViewController. Give it the identifier "EmbedH" in the Attributes Inspector.
Create a show segue between ViewController and the GreenViewController by Control dragging from the viewController icon at the top of ViewController to the GreenViewController. Name this segue "GoToGreen" in the Attributes Inspector.
In prepareForSegue for ViewController, when the "EmbedH" segue happens, set the delegate property of HViewController to self (ViewController).
When the user clicks the H button in the HViewController, call delegate?.segueToNext("GoToGreen") to trigger the segue in ViewController.
Here it is running in the simulator:
I was needing exactly what #vacawama proposed here, though I couldn't reproduce that, I tried exactly your steps but self.delegate?.segueToNext("GoToGreen") got called but neither the protocol itself nor the container view controller. After an entire day searching about this approach I realized the problem was with the swift version. Just replace this:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EmbedH" {
let dvc = segue.destination as! HViewController
dvc.delegate = self
}
}
for this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EmbedH" {
let dvc = segue.destination as! HViewController
dvc.delegate = self
}
}
Other detail I was missing was about the embedded segue. Be sure to connect the container View to the HViewController, not the View Controller itself, otherwise the Embed option for segue won't appear.
Hello learning swift and am stuck with calling a method through delegate. Checked multiple answers with similar issues and have tried the solutions but have not been able to successfully apply them to my own situation however I am close.
I have a delegator class named ViewController that holds a variable I would like to change. I have another view called MoodScroll which serves as the delegate. Moodscroll has a button being used to change the value for the variable in ViewController.
ViewController :
class ViewController: UIViewController, AVAudioPlayerDelegate, MoodScrollDelegate {
var alarmSoundType: String?
func acceptData(data: String?) {
alarmSoundType = "\(data)"
print(data)
}
}
MoodScroll :
protocol MoodScrollDelegate {
func acceptData(data: String?)
}
import UIKit
class MoodScroll: UIViewController {
#IBAction func WTF(sender: AnyObject) {
self.delegate?.acceptData("hello")
print("function called")
}
}
The IBAction calls fine as it prints "function called" in the console however it doesn't pass the value to ViewController as alarmSoundType remains nil and also the print command is not called in ViewController as well.
It seems you still have some confusion about delegation : if ViewController conforms to MoodScrollDelegate protocol, then your ViewController object will be the delegate, not the MoodScroll object.
Where do you set the delegate property of your MoodScroll object ?
If this object is created programmatically from your ViewController object, you should set it after initialization :
myMoodScrollObject.delegate = self
Is the object is created using Interface Builder, you can either use an outlet variable for delegate, or set it in prepareForSegue:sender of your ViewController class :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let scroll = segue.destinationViewController as? MoodScroll{
scroll.delegate = self
}
}
One picky note: the way you have described your problem, it's actually ViewController what you should call the delegate of MoodScroll. Most likely you're probably forgetting to set the delegate property of MoodScroll.
I don't know how these two view controllers relate to each other in your code, but very often you would set the delegate property in the prepareForSegue method of ViewController, for example:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SegueToMoodScroll" {
let moodScrollController = segue.destinationViewController as! MoodScroll
moodScrollController.delegate = self
}
}