why in don't pass value user.username to navigator - ios

class SigninViewController: UIViewController {
#IBOutlet weak var usernameTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
var signinAPIManager: SigninAPIManager?
override func viewDidLoad() {
super.viewDidLoad()
setupView()
setupData()
}
private func setupData() {
setupServices()
}
private func setupView() {
setupTextFields()
}
private func setupTextFields() {
let textFields = [usernameTextField, passwordTextField]
textFields.forEach{ $0?.delegate = self }
}
#IBAction func signinButton(_ sender: Any) {
signinAPIManager?.signin(optionalUsername: usernameTextField.text,
optionalPassword: passwordTextField.text)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "SigninCompletedIdentifier"{
if segue.destination is HomeTableViewController{
let vc = segue.destination as? HomeTableViewController
vc?.textUser = "asds"
}
}
}
}
}
extension SigninViewController: SigninAPIManagerDelegate {
func didSigninCompletion(user: User) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondController = storyboard.instantiateViewController(withIdentifier: "secondary") as! HomeTableViewController
secondController.textUser = user.username
performSegue(withIdentifier: "SigninCompletedIdentifier", sender: self)
}
}
I want to pass user.username in extension SigninViewController to navigator withIdentifier: "SigninCompletedIdentifier"

Please try to print your object first:
print("SignInApiManager Object= ", signinAPIManager)
You'll find it nil as you haven't assigned any instance of SigninAPIManager.
Replace the following line of code:
Replace var signinAPIManager: SigninAPIManager? with var signinAPIManager: SigninAPIManager = SigninAPIManager()

Related

How to assign value to an outlet after delegating it?

So my app has 3 screens: Main, Second, and Result (very simple)
On the Main screen, i show a label and button to change it
On the Second one I change label with textinput and pass it to Result
(has
navigation controller)
On the Last screen I show the result and 2 buttons: save and
cancel
My problem is I can't assign value to Main's outlet because it's nil, and I can't do anything with viewDidLoad() because it works only once when the app starts.
What can I do to fix this? is there any function to reload view so I can assign value in viewDidLoad?
Storyboard screenshot
The whole app is here: https://drive.google.com/file/d/1mvL2fVxjOHbL4dReCwJ8poIq9G9-ezny/view
MainVC:
class MainVC: UIViewController, ResultVCDelegate {
func passData(text: String) {
// label.text = text -- throws error
}
#IBOutlet weak var label: UILabel!
#IBAction func change(_ sender: Any) {
let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NavVC")
present(nextVC, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
SecondVC:
class SecondVC: UIViewController {
#IBOutlet weak var inputText: UITextField!
#IBAction func save(_ sender: Any) {
let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ResultVC") as! ResultVC
nextVC.labelText = inputText.text!
navigationController?.pushViewController(nextVC, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
ResultVC:
protocol ResultVCDelegate {
func passData(text: String)
}
class ResultVC: UIViewController {
var delegate: ResultVCDelegate?
var labelText = ""
#IBOutlet weak var label: UILabel!
#IBAction func saveAndGoHome(_ sender: Any) {
let mainVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "MainVC") as! MainVC
self.delegate = mainVC
delegate?.passData(text: labelText)
dismiss(animated: true, completion: nil)
}
#IBAction func cancel(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
label.text = labelText.isEmpty ? label.text : labelText
}
}
BTW: I did similar app with two screens and it worked like a charm... strange
Following on from my comment.
Looking at your code, the issue is that you are not passing a reference to your MainVC to your ResultVC, and instead you are creating a new instance of MainVC, this results in a a crash because the view controller hasn't been properly created. But you don't want to create a new instance, as you need a reference to the original MainVC that you created.
You can get this by passing the reference, you will need to update all three of your ViewControllers. Something like this should work. Note I haven't tested this but this is the general principle.
class MainVC: UIViewController, ResultVCDelegate {
func passData(text: String) {
label.text = text
}
#IBOutlet weak var label: UILabel!
#IBAction func change(_ sender: Any) {
let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NavVC")
nextVC.delegate = self // Here we add the delegate (the reference to MainVC)
present(nextVC, animated: true, completion: nil)
}
}
We need to add the delegate here and then forward it on to the ResultVC.
class SecondVC: UIViewController {
weak var delegate: ResultVCDelegate? // Add the delegate that will hold a reference to MainVC
#IBOutlet weak var inputText: UITextField!
#IBAction func save(_ sender: Any) {
let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ResultVC") as! ResultVC
nextVC.labelText = inputText.text!
nextVC.delegate = delegate // Here we pass the reference to MainVC
navigationController?.pushViewController(nextVC, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
We can remove the code for instantiating the MainVC from the storyboard and instead just use the delegate to pass the value back to MainVC.
class ResultVC: UIViewController {
weak var delegate: ResultVCDelegate?
var labelText = ""
#IBOutlet weak var label: UILabel!
#IBAction func saveAndGoHome(_ sender: Any) {
// Just use the delegate no need to create a new instance
delegate?.passData(text: labelText)
dismiss(animated: true, completion: nil)
}
#IBAction func cancel(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
label.text = labelText.isEmpty ? label.text : labelText
}
}
-> Main VC (Where you need to get data)
class MainVC: UIViewController, ResultVCDelegate {
func passData(text: String) {
// label.text = text -- throws error
print(text)
}
#IBOutlet weak var label: UILabel!
#IBAction func change(_ sender: Any) {
let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NavVC")
nextVC.delegate = self
present(nextVC, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
-> Result VC (from where you need to send data)
protocol ResultVCDelegate: AnyObject {
func passData(text: String)
}
class ResultVC: UIViewController {
weak var delegate: ResultVCDelegate?
var labelText = "Please Enter Something"
#IBOutlet weak var label: UILabel!
#IBAction func saveAndGoHome(_ sender: Any) {
self.delegate?.passData(text: labelText)
dismiss(animated: true, completion: nil)
}
#IBAction func cancel(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
label.text = labelText.isEmpty ? label.text : labelText
}
}

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.

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
}
}

Change Image From Previous View After Button Tap (Swift)

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?)
}

Passing user entered text to following segue

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
}
}
}

Resources