Passing user entered text to following segue - ios

I have a screen with a text field.
When a user inputs text into that text field, and taps out of the text field, a segue occurs.
The following screen's label text should be changed to the text entered by the user in the previous.
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
print(info)
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
}
}
}
}
}
The print(info) statement does not print anything
However, the segue works, but the label displays nothing.
class BlueViewController: UIViewController {
#IBOutlet weak var blueText: UILabel!
var receptacle = ""
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
blueText.text = receptacle
}
}
Clearly this has to do with timing... any ideas?

Your viewWillAppear function works first and that time your receptacle variable is not set or your label does not initialized. Try this;
#IBOutlet weak var blueText: UILabel! { didSet { blueText.text = receptacle } }
var receptacle: String? { didSet { blueText.text = receptacle } }

Change
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
blueText.text = receptacle
}
to
override func viewDidLoad() {
super.viewDidLoad()
blueText.text = receptacle
}

Don't use the sender to pass your value. The sender is only useful to check which element has started the segue, but not to pass data. Just make your info as a class-variable and pass the value like that:
var info:String!
func textFieldDidEndEditing(inputField: UITextField) {
info = inputField.text
print(info)
performSegueWithIdentifier("goToBlue", sender: info)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "goToBlue" {
if let blueVC = segue.destinationViewController as? BlueViewController {
blueVC.receptacle = info
}
}
}

Here is the very common way to do it (FYI, if the vc with inputTextfield is a popover, you can just call dismissViewController on the presenting vc)
func textFieldDidEndEditing(inputField: UITextField) {
textField.resignFirstResponder()
let info = inputField.text
print(info)
performSegueWithIdentifier("goToBlue", sender: info)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "goToBlue" {
if let blueVC = segue.destinationViewController as? BlueViewController {
blueVC.receptacle = self.inputField.text
}
}
}

Related

How to push data from textField to label in another VC

I have mainVC with 4 labels and 4 goToVC buttons, each button use segue to present another 1 of 4 VC. Every vc have textField and doneButton. I want to show text from textField in mainVC labels and i want to use delegates. But instead i got empty labels. Please help.
Delegate.swift
protocol TextFieldDelegate {
func didFinishTextField(text: String)
}
MainVC.swift
class MainViewController: UIViewController, TextFieldDelegate {
#IBOutlet weak var redText: UILabel!
#IBOutlet weak var orangeText: UILabel!
#IBOutlet weak var pinkText: UILabel!
#IBOutlet weak var purpleText: UILabel!
var choosenLabel: UILabel?
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toRedVC" {
let vc = segue.destination as! RedViewController
vc.delegate = self
choosenLabel = redText
} else if segue.identifier == "toOrangeVC" {
let vc = segue.destination as! OrangeViewController
vc.delegate = self
choosenLabel = orangeText
} else if segue.identifier == "toPinkVC" {
let vc = segue.destination as! PinkViewController
vc.delegate = self
choosenLabel = pinkText
} else if segue.identifier == "toPurpleVC" {
let vc = segue.destination as! PurpleViewController
vc.delegate = self
choosenLabel = purpleText
}
}
func didFinishTextField(text: String) {
if let data = choosenLabel {
data.text = text
}
}
#IBAction func redButton(_ sender: UIButton) {
}
#IBAction func orangeButton(_ sender: UIButton) {
}
#IBAction func pinkButton(_ sender: UIButton) {
}
#IBAction func purpleButton(_ sender: UIButton) {
}
}
RedVC(other 3 same).swift
class RedViewController: UIViewController {
var delegate: TextFieldDelegate?
var textVar: String = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func textField(_ sender: UITextField) {
if let data = sender.text {
textVar = data
}
}
#IBAction func doneButton(_ sender: UIButton) {
delegate?.didFinishTextField(text: textVar)
dismiss(animated: true, completion: nil)
}
}
Everything seems ok in your code. I suggest you to check your text field's actions are set to editingChanged in ViewController.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) not working

I have a table view controller that works like a news feed of images where each image has been retrieved from firebase. I want to be able to tap on each image and perform a segue to another view controller that has a table view with its own unique data of the tapped image.
With the code I have, the override func prepare(for:sender) is not being called and there is no error. The unique post id is being printed in the console when the image is tapped but the Show Segue is not being performed.
Here is my code in the HomeTableViewCell:
protocol HomeTableViewCellDelegate {
func goToSiteVC(postId: String)
}
class HomeTableViewCell: UITableViewCell {
#IBOutlet weak var siteImageView: UIImageView!
var delegate: HomeTableViewCellDelegate?
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.siteImageView_TouchUpInside))
siteImageView.addGestureRecognizer(tapGesture)
siteImageView.isUserInteractionEnabled = true
// Configure the view for the selected state
}
#objc func siteImageView_TouchUpInside() {
print("siteImageView_TouchUpInside")
print(post?.id)
if let id = post?.id {
delegate?.goToSiteVC(postId: id)
}
}
}
Here is my code in HomeViewController:
class HomeViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var posts = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
loadPosts()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "SiteSegue" {
let siteVC = segue.destination as! SiteViewController
let postId = sender as! String
siteVC.postId = postId
print("segue")
}
}
}
extension HomeViewController: HomeTableViewCellDelegate {
func goToSiteVC(postId: String) {
performSegue(withIdentifier: "SiteSegue", sender: postId)
}
}
The function should be out of viewDidLoad it must be in class scope
class HomeViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var posts = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
loadPosts()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "SiteSegue" {
let siteVC = segue.destination as! SiteViewController
let postId = sender as! String
siteVC.postId = postId
print("segue")
}
}
}

Xcode Swift pass String from popover view to main VC

Im trying to pass data from a string in my popOverViewController back to my mainVC as string. But i can't figure out how to do this, so please help anyone.
My mainVC segue func :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "popoverSegue" {
let popoverViewController = segue.destinationViewController
popoverViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
popoverViewController.popoverPresentationController!.delegate = self
}
}
My popOverVC:
Im trying to pass the valueSelected back to mainVC
var pickerString = NSArray() as AnyObject as! [String]
var valueSelected = String()
#IBOutlet weak var picker: UIPickerView!
#IBAction func pickButton(sender: AnyObject?) {
// need to send valueSelected back to previous navigated view
print("Value: ", valueSelected)
dismissViewControllerAnimated(true, completion: nil)
}
need to send valueSelected string back to previous navigated view.
For this you can use closures in swift. Here is how to do this:
FirstViewController.swift
class FirstViewController: UIViewController
{
override func viewDidLoad()
{
}
#IBAction func onButtonTap(_ sender: UIButton)
{
self.performSegue(withIdentifier: "popoverSegue", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "popoverSegue"
{
let popoverViewController = segue.destination as!PopOverViewController
popoverViewController.modalPresentationStyle = UIModalPresentationStyle.popover
popoverViewController.popoverPresentationController!.delegate = self
popoverViewController.completionHandler = {(valueSelected : String?) in
if let valueSelected = valueSelected
{
print(valueSelected)
//Write yout code here
}
}
}
}
}
PopOverViewController.swift
class PopOverViewController: UIViewController
{
var completionHandler : ((String?)->(Void))?
var pickerString = NSArray() as AnyObject as! [String]
var valueSelected = String()
#IBAction func pickButton(_ sender: UIButton)
{
print("Value: ", valueSelected)
self.dismiss(animated: true, completion: {[weak self] in
if let handler = self?.completionHandler
{
handler(self?.valueSelected)
}
})
}
}
If you want to use Delegate
add Protocol
protocol SelectDelegate: NSObjectProtocol {
func select(_ string: String)
}
add weak type Delegate to popOverVC and use it before dismissViewController
var pickerString = NSArray() as AnyObject as! [String]
var valueSelected = String()
weak var delegate: SelectDelegate?
#IBOutlet weak var picker: UIPickerView!
#IBAction func pickButton(sender: AnyObject?) {
print("Value: ", valueSelected)
//added Line
delegate?.select(valueSelected)
dismissViewControllerAnimated(true, completion: nil)
}
implement SelectDelegate to MainVC
class MainVC {
. . .
func select(string: String) {
//doSometing popupVC's string
}
}
assign popOverVC's delegate to mainVC
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "popoverSegue" {
let popoverViewController = segue.destinationViewController
popoverViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
popoverViewController.popoverPresentationController!.delegate = self
// added Line
popoverViewController.delegate = self
}
}

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