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"
}
}
Related
I am new to Swift and was wondering on how to pass data from ViewController to ViewController that isn’t connected by segue. I have spend 2 hours on this and still can’t figure a way to do it.
Edit: The problem that I am confused on is How to take out all the stacked ViewController expect the root ViewController while being able to pass data back to the first ViewController from ViewController3 with
'navigationController?.popToRootViewController(animated: false)'
class ViewController: UIViewController, nameDelegate {
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var textfield1: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
label1.text = "Name"
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc2 = segue.destination as! ViewController2
vc2.middleOfTransferingName = textfield1.text!
}
#IBAction func buttonPressed1(_ sender: Any) {
performSegue(withIdentifier: "go2", sender: self)
}
func nameThatWasEntered(name: String) {
label1.text = name
}
}
class ViewController2: UIViewController, nameDelegate {
var middleOfTransferingName: String = ""
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc3 = segue.destination as! ViewController3
vc3.transferedWithSegueLabelText = middleOfTransferingName
vc3.namePassBack = self
}
#IBAction func buttonPressed2(_ sender: Any) {
performSegue(withIdentifier: "go3", sender: self)
}
func nameThatWasEntered(name: String) {
}
}
protocol nameDelegate {
func nameThatWasEntered(name: String)
}
class ViewController3: UIViewController {
#IBOutlet weak var label3: UILabel!
#IBOutlet weak var textfield3: UITextField!
var transferedWithSegueLabelText: String = ""
var namePassBack: nameDelegate?
override func viewDidLoad() {
super.viewDidLoad()
label3.text = transferedWithSegueLabelText
}
#IBAction func buttonPressed3(_ sender: Any) {
namePassBack!.nameThatWasEntered(name: textfield3.text!)
navigationController?.popToRootViewController(animated: false)
}
}
I found the way to transfer ViewController3 data to ViewController!
var vc3 = ViewController3()
then making ViewController as the delegate of vc3 upon loading.
override func viewDidLoad() {
super.viewDidLoad()
vc3.namePassBack = self
}
Then going back to ViewController3, I add ""vc3."" before using the delegate.
#IBAction func buttonPressed3(_ sender: Any) {
vc3.namePassBack!.nameThatWasEntered(name: textfield3.text!)
navigationController?.popToRootViewController(animated: false)
}
if you use segue then use 'Unwind segue'
for this write given code in your 'A view controller'
#IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
}
In B_viewcontroller, On press button call 'Unwind segue'.
Note:- With the help of Unwind segue you can send the value for 3ed vc to 1se vc same as you send value form 1st vc to 2nd vc
for more go to this link
I am using a modal segue to create a view controller that I want to dismiss and then call a method in the origin view controller. I have used a protocol/delegate pattern but for some reason the method is never called. The code is below: Please note that I removed a lot of non-relevant code to keep it clean here
Thanks!!
VC1:
final class WorkoutViewController: UIViewController, StartWorkoutButtonDelegate {
weak var dataSource: WorkoutViewControllerDataSource!
private var workout: Workout!
private var workoutDataViewController: WorkoutDataViewController?
private var workoutFinishViewController: WorkoutFinishViewController?
private let workoutFinishViewControllerSegueIdentifier = "Workout Finish View Controller Segue"
#IBOutlet private var primaryActionButton: UIButton!
#IBOutlet private var pageControl: UIPageControl!
// MARK: - Handling View Lifecycle
override func viewDidLoad() {
super .viewDidLoad()
let workoutType = dataSource.workoutType(for: self)
workout = Workout(workoutType: workoutType, managedObjectContext: persistentContainer.viewContext)
setPrimaryActionButtonLabel()
}
// MARK: - Handling Storyboard Segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let destinationWorkoutFinishViewController = segue.destination as? WorkoutFinishViewController {
workoutFinishViewController = destinationWorkoutFinishViewController
}
}
// MARK: - Managing Start and Pause
#IBAction func startOrPauseWorkout() {
if workout.isPaused {
startWorkout()
} else {
pauseWorkout()
}
}
}
VC 2:
protocol StartWorkoutButtonDelegate: AnyObject {
func startOrPauseWorkout()
}
class WorkoutFinishViewController: UIViewController {
weak var delegate: StartWorkoutButtonDelegate?
#IBAction func startWorkout() {
self.delegate?.startOrPauseWorkout()
self.dismiss(animated: true, completion: nil)
}
#IBAction func finishWorkout() {
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Here set the delegate
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let destinationWorkoutFinishViewController = segue.destination as? WorkoutFinishViewController {
destinationWorkoutFinishViewController.delegate = self
}
}
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?)
}
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.
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.