Button Triggered Issues - ios

I'm getting data back from secondVC to firstVC and showing it in a text field.
My VC's are FirstVC with a text field and secondVC with a button.
The flow of my VC is when a user clicks on the text field (here text field action Editing Did Begin called) in firstVC then the secondVC will open. And then when the button clicks in secondVC then goes back to firstVC with some data and data will be show in same text field.
So the above is all working fine.
Now I want that the second time when again I click on the text field (now text field contains some data) so then again go to secondVC.
The problem is that now the text field contains data. When I click on it, it doesn't work because of button action property Editing Did Begin.
How to handle this?
Below is my code,
First VC
import UIKit
class firstViewController: UIViewController, UITextFieldDelegate, MyProtocol {
var valueSentFromSecondViewController : String?
#IBOutlet weak var myTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func myTextFieldACTIONWhenEditingDidBegin(_ sender: Any) {
myTextField.isUserInteractionEnabled = false
let secondVC = self.storyboard?.instantiateViewController(withIdentifier: "secondViewController") as! secondViewController
secondVC.delegate = self
self.navigationController?.pushViewController(secondVC, animated: true)
}
func setResultsAfterEvaluation(valueSent: String) {
self.valueSentFromSecondViewController = valueSent
print(valueSentFromSecondViewController!)
myTextField.text = valueSent
//print(valueSent)
}
}
Second VC
import UIKit
protocol MyProtocol {
func setResultsAfterEvaluation(valueSent: String)
}
class secondViewController: UIViewController {
var delegate : MyProtocol?
var sentValue : String?
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btn(_ sender: Any) {
sentValue = "Ahtazaz"
delegate?.setResultsAfterEvaluation(valueSent: sentValue!)
self.navigationController?.popViewController(animated: true)
}
}

I believe this is a more simple way to do what you are trying to achieve, as it doesn't involve protocols and extra functions. If you have any questions, please ask. :)
First View Controller:
import UIKit
//By declaring a variable outside of any class, it is always active in memory and accessible anywhere.
var textFieldText: String = ""
class ViewController1: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField1: UITextField!
func textFieldDidBeginEditing(_ textField: UITextField) {
//textField.resignFirstResponder is used to dismiss the keyboard. By putting it in this function, it hides the keyboard, which prevents users from entering custom text into your text field.
textField.resignFirstResponder()
let VC2 = self.storyboard?.instantiateViewController(withIdentifier: "ViewController2") as! ViewController2
self.navigationController?.pushViewController(VC2, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
//This links textField1 on your storyboard to the textFieldDidBeginEditing function.
textField1.delegate = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Every time the view is about to appear, this is called. This is where we update the text field's text.
textField1.text = textFieldText
}
}
Second View Controller:
import UIKit
class ViewController2: UIViewController {
#IBOutlet weak var button1: UIButton!
#IBOutlet weak var button2: UIButton!
//If the data you are trying to pass is the button's title, use these two functions.
#IBAction func button1Tapped(_ sender: UIButton) {
textFieldText = (button1.currentTitle)!
self.navigationController?.popViewController(animated: true)
}
#IBAction func button2Tapped(_ sender: UIButton) {
textFieldText = (button2.currentTitle)!
self.navigationController?.popViewController(animated: true)
}
//If the data you are trying to pass is not the button's title, use these.
#IBAction func button1Tapped(_ sender: UIButton) {
textFieldText = "Your Text Here"
self.navigationController?.popViewController(animated: true)
}
#IBAction func button2Tapped(_ sender: UIButton) {
textFieldText = "Your Text Here"
self.navigationController?.popViewController(animated: true)
}
}

Related

Why do I have to call my protocol functions two times to make it work?

I'm currently building a simple app to learn the protocol - delegate functionality. However my code doesn't work, even after I edited the way I did in my first practice app where it worked. In the FirstViewController there is a UILabel and a UIButton. When the user taps on the UIButton, a segue brings them to the SecondViewController where they should enter their name into a UITextField. After that, they can press the UIButton in the SecondViewController and the entered Name should be displayed in the UILabel in the FirstViewController.
I can't figure out why I have to call the protocol function two times in the #IBAction backButtonPresses(). Also, I can't figure out how to handle the same protocol function in the FirstViewController.
Here's the code for the FirstViewController.swift file:
import UIKit
class FirstViewController: UIViewController, SecondViewControllerDelegate {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var button: UIButton!
var labelText = ""
let secondVC = SecondViewController()
func changeLabelText(name: String) {
labelText = secondVC.enteredName
}
#IBAction func buttonPressed(_ sender: UIButton) {
performSegue(withIdentifier: "goToSecondVC", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as? SecondViewController
destinationVC?.delegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
nameLabel.text = secondVC.enteredName
}
}
And here's the code of the secondViewController:
import UIKit
protocol SecondViewControllerDelegate {
func changeLabelText(name: String)
}
class SecondViewController: UIViewController, SecondViewControllerDelegate {
var delegate: SecondViewControllerDelegate?
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var backButton: UIButton!
var enteredName: String = ""
func changeLabelText(name: String) {
enteredName = name
}
#IBAction func backButtonPressed(_ sender: UIButton) {
changeLabelText(name: nameTextField.text ?? "")
delegate?.changeLabelText(name: nameTextField.text ?? "")
print("das ist der name \(enteredName)")
dismiss(animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
You do not call any delegate method twice in backButtonPressed. You are calling two completely different changeLabelText methods. One is in SecondViewController, the other is on the delegate.
The call to changeLabelText in the SecondViewController is quite unnecessary. In fact, the enteredName property in SecondViewController is unnecessary. Also, SecondViewController should not be implementing its own delegate.
The call to changeLabelText on delegate is all you need. You just need to update the implementation of changeLabelText in FirstViewController to update the label's text with the new value.
func changeLabelText(name: String) {
nameLabel.text = name
}
Do not reference the secondVC property in FirstViewController. In fact, remove that property completely. It's not needed and it's referencing a completely different instance of SecondViewController than the one you actually present via segue.
I also suggest renaming the delegate method from changeLabelText to something more general such as enteredText. SecondViewController can be used by any other view controller to obtain some text. It's not specific to changing a label.
Here's your two view controllers with suggested changes:
class FirstViewController: UIViewController, SecondViewControllerDelegate {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var button: UIButton!
func enteredText(name: String) {
nameLabel.text = name
}
#IBAction func buttonPressed(_ sender: UIButton) {
performSegue(withIdentifier: "goToSecondVC", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as? SecondViewController
destinationVC?.delegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
protocol SecondViewControllerDelegate {
func enteredText(name: String)
}
class SecondViewController: UIViewController {
var delegate: SecondViewControllerDelegate?
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var backButton: UIButton!
#IBAction func backButtonPressed(_ sender: UIButton) {
let name = nameTextField.text ?? ""
delegate?.changeLabelText(name: name)
print("das ist der name \(name)")
dismiss(animated: true)
}
}

How to pass data using delegates and protocols

I have this first viewController which has UILabel in it and secondViewController which has UItextField and Add button. They are embedded in tabbar. I want to pass data from text field when add button is clicked to uilabel of first view controller.
protocol SendDelagate
{
func setData(string:String)
}
First View Controller is
class ViewController: UIViewController,SendDelagate{
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let vc = SecondViewController()
vc.delegates = self
}
func setData(string: String) {
label.text = string
}
}
And second ViewController is
class SecondViewController: UIViewController {
var delegates:SendDelagate?
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func addButton(_ sender: UIButton) {
let text = textField.text!
delegates?.setData(string: text)
}
}
SecondViewController is embedded in UITabbarController?
You can find SecondViewController instance via TabbarController
class ViewController: UIViewController, SendDelagate {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
if let secondViewController = tabBarController?.viewControllers?.first(where: { $0 is SecondViewController }) as? SecondViewController {
secondViewController.delegates = self
}
}
func setData(string: String) {
label.text = string
}
}
You can use User Defaults. So you save with your Add Button into User Defaults, and on viewDidLoad on the other view, you can load it.

How to pass Data from the SearchBar to UILabel?

how do you pass data from search Bar to UILabel in a different view controller
Passing Data between View Controllers
I have tried multiple questions here on stack, but it just doesn't work or the simulator ends up crashing for me
class FirstVC: UIViewController, DataEnteredDelegate {
#IBOutlet weak var label: UILabel!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showSecondViewController" {
let secondViewController = segue.destination as! SecondVC
secondViewController.delegate = self
}
}
func userDidEnterInformation(info: String) {
label.text = info
}
}
// protocol used for sending data back
protocol DataEnteredDelegate: class {
func userDidEnterInformation(info: String)
}
class SecondVC: UIViewController {
// making this a weak variable so that it won't create a strong reference cycle
weak var delegate: DataEnteredDelegate? = nil
#IBOutlet weak var searchBar: UISearchBar!
#IBAction func sendTextBackButton(sender: AnyObject) {
// call this method on whichever class implements our delegate protocol
delegate?.userDidEnterInformation(info: searchBar.text!)
// go back to the previous view controller
_ = self.navigationController?.popViewController(animated: true)
}
}
I don't find anything suspicious in your code which cause app crash. Meanwhile for data transfer between view controller we can use delegation and NotificationCenter. Below code uses NotificationCenter
let kStringTransfer = "StringTransferNotification"
class FirstViewController: UIViewController, DataEnteredDelegate {
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(setString(notify:)), name: NSNotification.Name(rawValue: kStringTransfer), object: nil)
}
func getSecondVC() {
if let second = self.storyboard?.instantiateViewController(withIdentifier: "Second") as? ViewController {
self.navigationController?.pushViewController(second, animated: true)
}
}
#IBAction func searchBarBtn(_ sender: Any) {
//go to search view controller
getSecondVC()
}
#objc func setString(notify: Notification) {
//set search bar string to text field
textField.text = notify.object as? String
}
}
class SecondViewController: UIViewController, UISearchBarDelegate {
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
searchBar.delegate = self
}
#IBAction func goBackBtn(_ sender: Any) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: kStringTransfer), object: searchBar.text)
self.navigationController?.popViewController(animated: true)
}
}
When I need pass just small values between 2 viewControllers, I don't use a delegate, just create a variable in second view and pass like this.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "showView") {
let vc = segue.destination as! secondViewController
vc.stringTemp = "My string"
}
}

View Controller delegate returns nil

My code is below. When I press the 'Done' or 'Cancel' buttons, it doesn't work as I want. I did some debugging, and delegate is nil even though I set it. Please help - thanks.
class ViewController: UIViewController,EditViewControllerDelegate {
#IBOutlet weak var label: UILabel!
//页面跳转时
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EditView" {
//通过seque的标识获得跳转目标
let controller = segue.destinationViewController as! EditViewController
//设置代理
controller.delegate = self
//将值传递给新页面
controller.oldInfo = label.text
}
}
func editInfo(controller:EditViewController, newInfo:String){
label.text = newInfo
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
func editInfoDidCancer(controller:EditViewController){
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
import UIKit
protocol EditViewControllerDelegate {
func editInfo(controller:EditViewController, newInfo:String)
func editInfoDidCancer(controller:EditViewController)
}
class EditViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
var delegate:EditViewControllerDelegate?
var oldInfo:String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if oldInfo != nil{
textField.text = oldInfo
}
}
#IBAction func done(sender: AnyObject) {
delegate?.editInfo(self, newInfo: textField.text!)
}
#IBAction func cancel(sender: AnyObject) {
delegate?.editInfoDidCancer(self)
}
}
Try this,
class ViewController: UIViewController,EditViewControllerDelegate {
var controller: EditViewController?
#IBOutlet weak var label: UILabel!
//页面跳转时
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EditView" {
//通过seque的标识获得跳转目标
controller = segue.destinationViewController as! EditViewController
//设置代理
controller.delegate = self
//将值传递给新页面
controller.oldInfo = label.text
}
}
func editInfo(controller:EditViewController, newInfo:String){
label.text = newInfo
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
func editInfoDidCancer(controller:EditViewController){
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
import UIKit
protocol EditViewControllerDelegate {
func editInfo(controller:EditViewController, newInfo:String)
func editInfoDidCancer(controller:EditViewController)
}
class EditViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
var delegate:EditViewControllerDelegate?
var oldInfo:String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if oldInfo != nil{
textField.text = oldInfo
}
}
#IBAction func done(sender: AnyObject) {
delegate?.editInfo(self, newInfo: textField.text!)
}
#IBAction func cancel(sender: AnyObject) {
delegate?.editInfoDidCancer(self)
}
}
I’m not able to tell from your code how you are handling the opening of EditViewController from your ViewController.
I’m guessing that your prepareForSegue:sender: is not getting called resulting in the delegate not getting set. To fix this, you will need to add a performSegueWithIdentifier:sender: call at the point where the segue needs to happen as in
self.performSegueWithIdentifier("EditView", sender: self)
You should replace whatever code is performing the opening of EditViewController with that call.
I have an app the uses showViewController:sender: to open up a second view controller from the first one even though there is a Show segue defined in my storyboard. The segue in my storyboard doesn’t get used in that case and prepareForSegue:sender: is never called as a result.
If I replace my
showViewController(myVC, sender: self)
with
performSegueWithIdentifier("mySegue", sender: self)
then prepareForSegue:sender: will get called. If I am setting a delegate, like you are, in prepareForSegue:sender:, the delegate will get set before the segue happens.

Segue anachronism

I am trying to pass text input from the following ViewController:
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var inputField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
inputField.delegate = self
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
view.addGestureRecognizer(tap)
}
func dismissKeyboard() {
inputField.resignFirstResponder()
}
func textFieldDidEndEditing(inputField: UITextField) {
let info = inputField.text
performSegueWithIdentifier("goToBlue", sender: info)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "goToBlue" {
if let blueVC = segue.destinationViewController as? BlueViewController {
if let sentValue = sender as? String {
blueVC.receptacle = sentValue
print(blueVC.receptacle)
}
}
}
}
}
To this ViewController:
class BlueViewController: UIViewController {
#IBOutlet weak var blueText: UILabel!
var receptacle = "fail"
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
print(receptacle)
blueText.text = receptacle
print(receptacle)
}
}
The print statement in the first ViewController outputs correctly, however the output for the print statements in the second ViewController is fail fail, and the label in the second view reads "fail".
Due to this, I have reason to believe this is a timing issue.
Am I right? How do I fix this?
If you want to trigger your segue programmatically, you need to wire your goToBlue segue from the ViewController icon of your from ViewController to the BlueViewController:
Remember to set the Identifier of the Storyboard Segue in the Attributes Inspector to goToBlue.

Resources