I have this code:
MainViewControler:
class MainViewControler: UIViewController, ContainerToMaster {
#IBOutlet weak var systemContainerView: UIView!
#IBOutlet weak var favoriteProductBtn2: UIButton!
weak var containerViewController: Calculator1ViewController?
func changeBtn() {
favoriteProductBtn2.isHidden = true
print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
}
}
CallculatorViewController:
#IBOutlet weak var containerView: UIView!
class CallculatorViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
Calculator1ViewController:
protocol ContainerToMaster {
func changeBtn()
}
class Calculator1ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
containerToMaster?.changeBtn()
}
}
I have such an application layout:
Main view = MainViewControler.
In MainViewControler, I have a containerView (systemContainerView) in which the MainViewControler is located
In the CallculatorViewController, I have the next containerView in which the Calculator1ViewController is located.
When entering the Calculator1ViewController the function: containerToMaster?.changeBtn() should start (it should work in MainViewControler).
The problem is - this function does not work :(
Does anyone know how to fix it?
A contained viewController is embedded with an embed segue. You need to override prepare(for:sender) and set self as the containerToMaster delegate in the destination viewController. Your situation is complicated by the fact that you have a container view embedded in another container view, so you'll need to set up two delegates and pass the button call back:
protocol ContainerToMaster {
func changeBtn()
}
class MainViewControler: UIViewController, ContainerToMaster {
#IBOutlet weak var systemContainerView: UIView!
#IBOutlet weak var favoriteProductBtn2: UIButton!
weak var containerViewController: Calculator1ViewController?
func changeBtn() {
favoriteProductBtn2.isHidden = true
print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destVC = segue.destination as? CallculatorViewController {
destVC.containerToMaster = self
}
}
}
class CallculatorViewController: UIViewController, ContainerToMaster {
weak var containerToMaster: ContainerToMaster?
override func viewDidLoad() {
super.viewDidLoad()
}
func changeBtn() {
// pass the button call back
containerToMaster?.changeBtn()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destVC = segue.destination as? Calculator1ViewController {
destVC.containerToMaster = self
}
}
}
class Calculator1ViewController: UIViewController {
weak var containerToMaster: ContainerToMaster?
override func viewDidLoad() {
super.viewDidLoad()
containerToMaster?.changeBtn()
}
}
Related
I am trying to use segues to pass the data entered in the partyID text field to the partyID label in a separate view controller. However, I am getting errors in my code.
class PartyViewController: UIViewController {
// CALLS LOGIN VC
var LoginViewController: LoginViewController?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBOutlet weak var partyID: UITextField!
var token = String()
#IBAction func startParty(_ sender: UIButton) {
self.performSegue(withIdentifier: "partyVCtoGuestPartyVC", sender: self)
performSegue(withIdentifier: "hostStartParty", sender: self)
//LoginViewController?.fetchSpotifyProfile(accessToken )
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "partyVCtoGuestPartyVC"){
let GuestPartyVC = segue.destination as! GuestPartyViewController
GuestPartyVC.partyID = partyID.text
}
And here is the view controller I am trying to pass the data to:
class GuestPartyViewController: UIViewController {
#IBOutlet weak var partyID: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
partyIDLabel.text = partyID
// Do any additional setup after loading the view.
}
I get errors in my override func in LoginVC and then in the partyIDlabel.text in the GuestPartyVC.
In GuestPartyViewController
class GuestPartyViewController: UIViewController {
#IBOutlet weak var partyIDLabel: UILabel!
var partyID: String?
override func viewDidLoad() {
super.viewDidLoad()
partyIDLabel.text = partyID ?? ""
}
}
In PartyViewController
class PartyViewController: UIViewController {
#IBOutlet weak var partyID: UITextField!
#IBAction func startParty(_ sender: UIButton) {
self.performSegue(withIdentifier: "partyVCtoGuestPartyVC", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "partyVCtoGuestPartyVC",
let GuestPartyVC = segue.destination as? GuestPartyViewController {
GuestPartyVC.partyID = partyID.text
}
}
}
The IBOutlet is weak and may not be instantiate when you pass the text.
Could you try to pass the text in a property, then assign it in the viewDidLoad ?
class GuestPartyViewController: UIViewController {
#IBOutlet weak var partyID: UILabel!
var passedText: String?
override func viewDidLoad() {
super.viewDidLoad()
if let unwrappedPassedText = passedText {
partyIDLabel.text = partyID
}
}
// In the other controller
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "partyVCtoGuestPartyVC") {
let GuestPartyVC = segue.destination as! GuestPartyViewController
GuestPartyVC.passedText = partyID.text
}
first change the call of login VC
var LoginViewController = LoginViewController()
then put this before the view did load method
#IBOutlet weak var partyID: UITextField!
and can you send the error that you get
I am completely new to Swift programming and tried to delegate a single String from one ViewController to another by clicking a send button. The problem is , that it does not work ...
I guess it would be easy for you to solve this and considering that it would be very helpful wether you explain me what I did wrong. :)
Thank you a lot
import UIKit
protocol protoTYdelegate {
func didSendMessage(message: String)
}
class New: UIViewController {
#IBOutlet weak var SendButton: UIButton!
var tydelegate: protoTYdelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func SendButtonAction(_ sender: Any) {
let nachricht = "It works fine."
tydelegate?.didSendMessage(message: nachricht)
}
}
import UIKit
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let controller = New()
controller.tydelegate = self
}
}
extension ThankYouPage: protoTYdelegate{
func didSendMessage(message: String) {
numbersView.text = message
}
As far as I understand, this code block doesn't work but the problem is not in the code, it's actually way that you choose to send data. In iOS development, there are many ways to send data. In your case, you need to use prepareForSegue method to send data to new class, not necessary to use delegates.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "ThankYouPage") {
let vc = segue.destination as! ThankYouPage
vc.message = "Message that you want to send"
}
}
And you need to implement your ThankYouPage as:
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
var message = ""
override func viewDidLoad() {
super.viewDidLoad()
numbersView.text = message
}
}
In addition to that, you can use didSet method to print out the message to label instead of printing it directly in viewDidLoad method. Simply:
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
var message: String?{
didSet{
numbersView.text = message
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
I hope this helps you.
#Eyup Göymen's answer is right.
I have another way, assuming that you are not using segue and you are pushing to next controller by manual-code.
So your ThankYouPage code should be like :
import UIKit
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func someButtonAction(_ sender: Any) { // By clicking on some, you are opening that `New` controller
let detailView = self.storyboard?.instantiateViewController(withIdentifier: "New") as! New
detailView.tydelegate = self
self.navigationController?.pushViewController(detailView, animated: true)
}
}
extension ThankYouPage: protoTYdelegate {
func didSendMessage(message: String) {
numbersView.text = message
}
}
I want to the image thats in my UIImageView on my previous View after I tap on a button.
Any help? Thanks.
MainViewController.swift
class MainViewController: UIViewController {
#IBOutlet weak var hatBackground: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
hatBackground.image = UIImage(named: "black-hat-front.jpg")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showPatches"{
if let childViewController = segue.destination as? ChildViewController{
}
}
}
}
ChildViewController.swift
class ChildViewController: UIViewController {
#IBOutlet weak var doubleCupButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Choose a Patch"
}
#IBAction func doubleCupButtonPressed(_ sender: AnyObject) {
hatBackground.image = UIImage(named: "badgal-hat.jpg")??
// Go back to previous Controller
navigationController?.popViewController(animated: true)
}
}
If I good understood , you want choose image in ChildViewController and show it in MainViewController. To do that you should implement delegate pattern like this:
MainViewController
class MainViewController: UIViewController, ChildViewControllerDelegate {
#IBOutlet weak var hatBackground: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
hatBackground.image = UIImage(named: "black-hat-front.jpg")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showPatches"{
if let childViewController = segue.destination as? ChildViewController{
childViewController.delegate = self
}
}
}
func didSelectImage(image: UIImage?) {
self.hatBackground.image = image
}
}
ChildViewController
class ChildViewController: UIViewController {
#IBOutlet weak var doubleCupButton: UIButton!
var delegate: ChildViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Choose a Patch"
}
#IBAction func doubleCupButtonPressed(_ sender: AnyObject) {
let selectedImage = UIImage(named: "badgal-hat.jpg")
delegate?.didSelectImage(image: selectedImage)
self.navigationController?.popViewController(animated: true)
}
}
ChildViewControllerDelegate
protocol ChildViewControllerDelegate {
func didSelectImage(image:UIImage?)
}
It shows that the source view controler does not have the string variable so what should I do?
This is the code in my source view controller
#IBOutlet var textfield: UITextField!
#IBOutlet var tofirstbutton: UIButton!
#IBOutlet var tosecondbutton: UIButton!
var s:String!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "unwindtosecond"{
self.s=self.textfield.text
}
}
and this is the code in my destination view controller
#IBOutlet var textfield: UITextField!
#IBOutlet var tofirstbutton: UIButton!
#IBOutlet var tothirdbutton: UIButton!
#IBOutlet var label: UILabel!
#IBAction func unwindtosecond(Segue:UIStoryboardSegue){
if Segue.identifier == "unwindtosecond" {
var source:ViewController = Segue.sourceViewController as ViewController
var s:String = source.s!
}
I am getting an error saying that viewcontroller does not have a member named s.
Here is some example code to implement a main controller segueing to a second VC, and the second unwinding to the main controller. Notice that in the function the second cVC unwinds to, you can refer to the second controller and access a variable in the second controller. If you want to initialize a variable in the second VC from the main VC, you can use a prepareForSegue in the main VC.
import UIKit
class ViewController: UIViewController {
var varInMainVC = ""
#IBAction func segueToSecondVCAction(sender: UIButton) {
performSegueWithIdentifier("segueToSecondVC", sender: self)
}
#IBAction func unwindFromSecondVC(segue: UIStoryboardSegue) {
// return here from second VC
let vc = segue.sourceViewController as! SecondViewController
varInMainVC = vc.varInSecondVC
println("varInMainVC = \(varInMainVC)")
}
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.
}
}
import UIKit
class SecondViewController: UIViewController {
var varInSecondVC = ""
var varLoadedFromMainVC = 0
override func viewDidLoad() {
super.viewDidLoad()
varInSecondVC = "Test String to be returned"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Try these solutions:
Protocol delegate: https://stackoverflow.com/a/24299231/1925852
Setup a closure as a property: https://stackoverflow.com/a/24318588/1925852
Why can't I pass data from one view controller class to another view controller class when they are in the same .swift file?
I've done both of the tutorials linked bellow in an effort to understand passing data, and both have you make another .swift file for you second view controller. When I followed them exactly it works. When I do everything the same but just put the class SecondViewController in the same .swift file as the class FirstViewController it doesn't work. Why?
I'm building an application with three view controllers and I'd rather just keep all the code in one file if I can. Is this why it's not working or is it just bad form?
Tutorials:
How to Pass Data from View Controller (Swift : Xcode) on YouTube
Segue Between Swift View Controllers on CodingExplorer
This works:
// ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet var TextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var DestViewController: ViewTwo = segue.destinationViewController as ViewTwo
DestViewController.LabelText = TextField.text
}
}
// ViewTwo.swift
import UIKit
class ViewTwo: UIViewController {
#IBOutlet var Label: UILabel!
var LabelText = String()
override func viewDidLoad() {
Label.text = LabelText
}
}
This does not:
// ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet var TextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var DestViewController: ViewTwo = segue.destinationViewController as ViewTwo
DestViewController.LabelText = TextField.text
}
}
class ViewTwo: UIViewController {
#IBOutlet var Label: UILabel!
var LabelText = String()
override func viewDidLoad() {
Label.text = LabelText
}
}
Working fine for me.
Have you set the classes for your views properly? The view with your textField (and probably a button to ViewTwo) should be set to ViewController and your second view with the label should be set to ViewTwo.
Check the connections between your label/textField. Are they properly connected to your class?
This is the code I used, which should be exactly the same:
import UIKit
class ViewController: UIViewController {
#IBOutlet var TextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var DestViewController = segue.destinationViewController as! ViewTwo
DestViewController.LabelText = TextField.text
}
}
class ViewTwo: UIViewController {
#IBOutlet var Label: UILabel!
var LabelText = String()
override func viewDidLoad() {
Label.text = LabelText
}
}