access textfield text from another viewController - ios

I try to access a textfield content in my view profileView from my first view viewController but it doesn't work.
I read that I have to use override func prepare(for segue: UIStoryboardSegue, sender: Any?) {} so I did but it still not working and I don't understand why.
Here is my viewController code:
// This code is the code generated by xCode, only the loginField was added.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var loginField: UITextField!
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.
}
}
and here is my profileController prepare func:
var login: String!
#IBOutlet weak var myLabel: UILabel!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("prepare")
if (segue.identifier == "mainMenu")
{
let svc = segue.source as! ViewController
login = svc.loginField.text
self.myLabel.text = login
print(login)
}
}
Actually, the thing i really read was "prepareForSegue" func but when I try to override it, xCode won't compile the code...
Thanks for your help.

write your prepareforSegue method in your viewController
why?
Because you want to send ViewController textfield data to profileViewController.That is write your prepareForSegue in Source. Here,
Source = ViewController
Destination = ProfileView
Note:
Use a variable in your destinationViewController(ProfileView Controller) and keep the textField data in this variable.
like this in prepareForSegue.
destinationVC.someVariable = self.SourceViewLabel.text // your sourceViewController
and in viewDidLoad of your destinationViewController(ProfileView) write this.
self.profileLabel.text = somVariable
In my first view i wrote this.
#IBAction func nexVCAction(_ sender: Any) {
self.performSegue(withIdentifier: "secondvc", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "secondvc" {
let vc = segue.destination as! secondVC
vc.stringHolder = textField.text!
}
}
And this is the second view code.
import UIKit
class secondVC: UIViewController {
#IBOutlet weak var textlabel: UILabel!
var stringHolder:String = ""
override func viewDidLoad() {
super.viewDidLoad()
textlabel.text = stringHolder
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I made git project for this.
Check only FirstVC.swift and secondVC.swift
And this is the output.

You cannot set the text of the UITextField and any other components of UIKit in the prepare for segue, because all View components of the recently allocated controller are not initialised yet they are all nil in prepareForSegue. they allocated only be when the viewController is presented.
You set Text for current ViewController TextField at prepareForSegue. Instead of this you should set text at viewWillAppear method while pop or dismiss the presented ViewController by using Notification, Delegate or userDefaults etc...

You just need a small fix since UITextField and any other components of UIKit are not initialised yet in the prepare for segue:
var login: String!
#IBOutlet weak var myLabel: UILabel!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("prepare")
if (segue.identifier == "mainMenu")
{
let svc = segue.source as! ViewController
login = svc.loginField.text
// self.myLabel.text = login
print(login)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.myLabel.text = login
}

Data flow from one controller to another is the very popular theme for ios beginners. There are several approaches to achieve this goal: segues, delegate pattern, notifications, initialization of new instance of controller, saving data to local storage etc.
You should user prepare(for segue: sender:) method only when you have segue from you current controller to another. You can get access to destination controller instance via destination property of segue parameter.
Also never call IBOutlet properties of destination controller in prepareForSegue - it can be cause of crash, because Outlets may be uninitilized at this time. Instead use String property for example.
Here is sample code:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "mainMenu") {
if let destinationVC = segue.destination as? ViewController {
destinationVC.login = self.myLabel.text
}
}
}
Where login in destinationVC is the String variable to store login.

Related

Delegate method is not called swift ios?

We have two controller - ControllerA and ControllerB. Controller A contains the normal button and text field(mail id). When we enter the mailid and tap the button. we will present the ViewControllerB and we have an option called to change the email and click back. We are using a delegate to pass the viewControllerB value to ViewController. But delegate function is not called.
ViewControllerB :
protocol countryViewControllerDelegate{
func passMailId(code: String)
}
var delegate: countryControllerDelegate?
#IBAction func createNewFolder(_ sender: Any?) {
delegate?.countryCode(code: emailText.text)
self.dismiss(animated: true, completion: nil)
}
ViewControllerA :
var instance = ViewControllerB()
override func viewDidLoad() {
instance.delegate = self
}
func showCoutryPicker(){
self.performSegue(withIdentifier: "DropDown", sender: self)
}
extension ViewControllerA:countryViewControllerDelegate{
func countryCode(code: String) {
print(code)
}
}
Is any other way to fix this?
Your segue instance is different than the 1 here
var instance = ViewControllerB()
So you should either present
self.present(instance,animated:true,completion:nil)
OR
inside prepareForSegue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "DropDown" {
let des = segue.destination as! ViewControllerB
des.delegate = self
}
}
Simply use prepare(for segue: ) check the code below,
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "DropDown"){
let vc = segue.destination as! ViewControllerB
vc.delegate = self
}
}
The problem you had is that you are creating an instance from ViewControllerB
var instance = ViewControllerB()
And segue on the other hand, it wont work because it would be considered as a new instance rather than the segue destination.
You can use either delegate or instance in the below code. It will be useful for anyone:
ViewController :
class ViewController: UIViewController {
#IBOutlet weak var myTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
myTextField.text = "Hello World"
// Do any additional setup after loading the view, typically from a nib.
}
// Without segue
#IBAction func passData(_ sender: Any) {
let sb = storyboard?.instantiateViewController(withIdentifier: "viewcontroller2") as! ViewController2
sb.passText = "Hello World"
//set self to Delegate
sb.delegate = self
//set self to Instance
sb.instance = self
present(sb, animated: true, completion: nil)
}
// With segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let sb = segue.destination as! ViewController2
sb.passTextSegue = "Hello World with segue"
//set self to Delegate
sb.delegate = self
//set self to Instance
sb.instance = self
}
}
extension ViewController : ViewController2Delegate{
func passValue(Str: String) {
print(Str)
}
}
ViewController2 :
protocol ViewController2Delegate : class {
func passValue(Str:String)
}
class ViewController2: UIViewController {
//Create instance for Delegate
weak var delegate : ViewController2Delegate?
//Create instance for ViewController
var instance: ViewController?
override func viewDidLoad() {
super.viewDidLoad()
myTextField.text = passText
myTextFieldSegue.text = passTextSegue
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var myTextField: UITextField!
var passText: String?
#IBOutlet weak var myTextFieldSegue: UITextField!
var passTextSegue: String?
#IBAction func manage(_ sender: UIButton) {
//Pass value using Delegate
delegate?.passValue(Str: "Happy Coding~")
//Pass value using Instance
instance?.myTextField.text = "Happy Coding~ :)"
dismiss(animated: true, completion: nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}

Change Label text in a ContainerView on click of a button from other class (Uiviewcontroller)

I got small containerView with UILabel on main app screen. I got UIButton on main UIViewController. I want to change text of label that belongs to containerView class by clicking button in UIViewController.
I try to make it with delegation, but for some reason i got a mistake (Unwraping optional)...
I try to make it with Protocol, bud method "addText" in ContView dont works((((((
class ViewController: UIViewController {
var delegate: DelegateProtocol?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func button(_ sender: Any) {
delegate?.addText(String2: "123")
}}
///////////////////////////////////////////////////////////////////////
protocol DelegateProtocol {
func addText(String2: String)
}
//////////////////////////////////////////////////////////////////////
class ContViewController: UIViewController, DelegateProtocol {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "con" {
let vc = segue.destination as! ViewController
vc.delegate = self
}
}
func addText(String2: String) {
label.text = String2
}
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
first make an global variable in your view controller
private var viewController: YourVC?
then give your container view segue an identifier and do follwing
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourviewcontroller Segue identifiew" { //your container view segue identifier
viewController = segue.destination as? SelectedImageVC
}
}
now you can use you viewController to access label in your containerview controller like
if let controller = viewController {
controller.yourlabel.text = "text you want"
}

iOS 11.3 - performSegue from ContainerViewController from parentViewController

I have a parent view (with ViewController) which has a sidebar menu and containerView(ContainerViewController) in it. at the containerView, I have 2 segue link with their own view and viewController (Screen1 with Screen1ViewController, Screen2 with Screen2ViewController).
I have buttons to launch screen1 and screen2 from ViewController but somehow the setting performSegue() function seems like not firing.
ViewController
import UIKit
class ViewController: UIViewController {
var container : ContainerViewController!
#IBOutlet var SideBar: UIView!
#IBOutlet weak var viewConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
container = self.storyboard?.instantiateViewController(withIdentifier: "ContainerViewController") as! ContainerViewController
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "tocontainer"{
self.container = segue.destination as! ContainerViewController
}
}
#IBAction func launchScreen1(_ sender: Any) {
container.performSegue(withIdentifier: "toscreen1", sender: self)
}
#IBAction func launchScreen2(_ sender: Any) {
container.performSegue(withIdentifier: "toscreen1", sender: nil)
}
}
ContainerViewController
import UIKit
class ContainerViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
func launchScreen2() {
print("launchscreen2")
self.performSegue(withIdentifier: "toscreen1", sender: self)
}
}
As you can see i even tried a function launchScreen2 for the button to call. the print message did appear in console but somehow no effect on the self.performSegue.
I believe is the way I prepare the segue is wrong, I just don't know what else to try.

prepareForSegue won't pass data in Swift 4

I'm trying to pass a text from a text field in a view controller to a label in a second view controller via prepareForSegue, but it's not working.
My code so far:
class ViewController: UIViewController {
#IBOutlet weak var inputTextField: UITextField!
// use of override func prepare gives an error
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var DestViewController: secondViewController = segue.destination as! secondViewController
DestViewController.labelText = inputTextField.text!
}
}
class SecondViewController: UIViewController {
#IBOutlet weak var receivedTextLabel: UILabel!
var labelText = "ss"
override func viewDidLoad() {
super.viewDidLoad()
receivedTextLabel.text! = labelText
}
}
If I use override for prepareForSegue, I get the following error:
Method does not override any method from it's superclass
Without overriding, it builds, but after performing the segue from the button to SecondViewController, the label's text doesn't get updated.
The method changed back in Swift 3 from prepareForSegue(segue:sender) to prepare(for:sender:). Replace it with the following:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)

store segued data on a separate viewcontroller (swift4)

My code takes text from a textfield and segues to a separate view controller. The problem is that it can only store 1 segue entry. The new one replace the old every time the button is pressed. How on vc2 can I store every new entry to the segue.
VC
import UIKit
class ViewController: UIViewController {
#IBOutlet var txt: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func pressButton(_ sender: Any) {
if txt.text != "" {
performSegue(withIdentifier: "segue", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let secondController = segue.destination as! twoViewController
secondController.myString = txt.text!
}
}
twoVC
import UIKit
class twoViewController: UIViewController {
#IBOutlet var labelSmtih: UILabel!
var myString = String()
override func viewDidLoad() {
super.viewDidLoad()
labelSmtih.text = myString
}
}
If the second view controller is a UISplitViewController for example you should be able to append the text of the button to the label, by doing something in the lines of:
#IBAction func pressButton(_ sender: Any) {
if txt.text != "" {
performSegue(withIdentifier: "segue", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let secondController = segue.destination as! twoViewController
secondController.myString += txt.text!
}
}
If you really have a separated view controller it will probably lose the data once you go back to the first VC. In that case, I suggest you save the current text of the label on viewWillDisappear of the 2nd VC and then retrieve this on the prepareforsegue function on the first VC. More info here: Swift: How to store user preferences?

Resources