Swift believes non-nil value is actually nil - ios

I have two text boxes, passwordTextField and emailTextField. Values are entered into each. When I hit print, the values print in the console.
However, I am receiving the following error when using the next function to populate a text box on the next view controller.
Note
This was working not a few hours ago and I have changed nothing, so I am unsure how or why this now does not work.
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var registerButton: UIButton!
#IBAction func registerButtonPressed(_ sender: Any) {
let next = self.storyboard?.instantiateViewController(withIdentifier: "ABC") as! ABCViewController
self.present(next, animated: true,completion: nil)
let nameText = self.emailTextField.text!
let passwordText = self.passwordTextField.text!
print(nameText) // prints email
print(passwordText) // prints password
next.username.text = nameText // prints error: Unexpectedly found nil while implicitly unwrapping an Optional value
next.password.text = passwordText
}
Unexpectedly found nil while implicitly unwrapping an Optional value.
But non-nil values are displaying when printing out.

The code is unreliable because it's not guaranteed that the view in the second controller is loaded right after the present line.
All outlets are nil until the view is available.
Declare temporary properties in ABCViewController and populate the text fields in viewDidLoad
class ABCViewController : UIViewController {
#IBOutlet weak var username: UITextField!
#IBOutlet weak var password: UITextField!
var tempName = ""
var tempPassword = ""
// .....
func viewDidLoad() {
super.viewDidLoad()
username.text = self.tempName
password.text = self.tempPassword
}
}
In registerButtonPressed assign the values to the temporary properties and present the controller, nothing else.
#IBAction func registerButtonPressed(_ sender: Any) {
let next = self.storyboard?.instantiateViewController(withIdentifier: "ABC") as! ABCViewController
next.tempName = self.emailTextField.text!
next.tempPassword = self.passwordTextField.text!
self.present(next, animated: true,completion: nil)
}

Related

Crashing when passing Var data as delegates

I have been trying to pass data back to my "HostRideViewController" from my "ProfileViewController" but the data I try to pass back creates a fatal error when unwrapping it, but i dont understand why as the console print out before it shows the correct data
import UIKit
import Foundation
import Firebase
protocol RiderSelectionDelegate {
func selectedRideLeader(firstName:String,lastName:String,uid:String)
}
class ProfileViewController: UIViewController {
#IBOutlet weak var ProfilePictureImageView: UIImageView!
#IBOutlet weak var AddasLeaderBtn: UIButton!
#IBOutlet weak var FirstNameFeild: UILabel!
#IBOutlet weak var LastNameFeild: UILabel!
#IBOutlet weak var UserBioFeild: UILabel!
#IBOutlet weak var HiddenEmail: UILabel!
#IBOutlet weak var HiddenUID: UILabel!
var user: MyUser?
var selectedFirstName: String?
var selectedLastName: String?
var selectedUID: String?
var selectedEmail: String?
var selectionDelegate: RiderSelectionDelegate!
override func viewDidLoad() {
super.viewDidLoad()
/// make profile picture circular
ProfilePictureImageView.layer.cornerRadius = ProfilePictureImageView.frame.size.width/2
ProfilePictureImageView.clipsToBounds = true
/// load user data into view
FirstNameFeild?.text = user?.firstName
LastNameFeild?.text = user?.lastName
HiddenUID?.text = user?.uid
HiddenEmail?.text = user?.email
}
#IBAction func SelectedLeaderpressed(_ sender: Any) {
selectedFirstName = FirstNameFeild.text
selectedLastName = LastNameFeild.text
selectedUID = user?.uid
selectedEmail = user?.email
print(selectedUID!,selectedLastName!,selectedFirstName!)
/// where the error is happening
selectionDelegate.selectedRideLeader(firstName:selectedFirstName!, lastName:selectedLastName!, uid:selectedUID!)
dismiss(animated: true, completion: nil)
}
}
My console output and error from passing data
49s64wH2g7hjiMAKp0uvADkzP0k2 bloggs joe
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file
My intended use of the delegate is to set a label up with the user's name
extension HostRideViewController:RiderSelectionDelegate{
func selectedRideLeader(firstName: String, lastName: String, uid: String) {
OtherRideLeaderLbl.text = firstName
}
}
where am I going wrong as I'm trying to force unwrap the data which is there and present in the print but crashes when I'm trying to delegate it
It seems selectionDelegate is nil you need to set it when you present/push/segue to the destination vc

How to send data from TextField from second view controller to first view controller and add this data to array swift iOS [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 3 years ago.
I want to send data from TextField from second view controller to first view controller and add this data to an array
I have a struct which I will save to array:
struct ContactsModel {
var name : String
var surname : String
var phoneNumber : String
}
first VC:
class FirstViewController: UIViewController {
var contacts : [ContactsModel] = []
}
second VC:
class SecondViewController: UIViewController {
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var surnameTextField: UITextField!
#IBOutlet weak var phoneNumberTextField: UITextField!
#IBAction func saveAndClose(_ sender: UIButton) {
// here i want to send this objects (nameTextField, surnameTextField, phoneNumberTextField) in array in first VC when i press this button
}
}
You can accomplish this using a delegate:
struct ContactsModel {
var name : String
var surname : String
var phoneNumber : String
}
protocol SecondViewControllerDelegate: class {
func savedAndClosed(with model: ContactsModel)
}
class FirstViewController: UIViewController {
var contacts : [ContactsModel] = []
// Whereever you create and present your instance of SecondViewController make it conform to the delegate
func showSecondVC() {
let secondVC = SecondViewController()
secondVC.delegate = self
present(secondVC, animated: true, completion: nil)
}
}
extension FirstViewController: SecondViewControllerDelegate {
func savedAndClosed(with model: ContactsModel) {
contacts.append(model)
}
}
class SecondViewController: UIViewController {
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var surnameTextField: UITextField!
#IBOutlet weak var phoneNumberTextField: UITextField!
weak var delegate: SecondViewControllerDelegate?
#IBAction func saveAndClose(_ sender: UIButton) {
// here i want to send this objects (nameTextField, surnameTextField, phoneNumberTextField) in array in first VC when i press this button
guard let name = nameTextField.text, let surname = surnameTextField.text, let phoneNumber = phoneNumberTextField.text else { return }
let new = ContactsModel(name: name, surname: surname, phoneNumber: phoneNumber)
delegate?.savedAndClosed(with: new)
}
}
First be sure to make var contacts in FirstViewController static:
class FirstViewController: UIViewController {
static var contacts : [ContactsModel] = []
}
Then in SecondViewController you can edit variable "contacts" like this:
class SecondViewController: UIViewController {
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var surnameTextField: UITextField!
#IBOutlet weak var phoneNumberTextField: UITextField!
#IBAction func saveAndClose(_ sender: UIButton) {
// here i want to send this objects (nameTextField, surnameTextField, phoneNumberTextField) in array in first VC when i press this button
FirstViewController.contacts.append(ContactsModel(name: nameTextField.text ?? "defaultName", surname: surnameTextField.text ?? "defaultSurname", phoneNumber: phoneNumberTextField.text ?? "defaultPhone"))
}
}
You need to define default values so even if text from field would be nil your app won't crush, in example we set default values here:
name: nameTextField.text ?? "defaultName"

SIGABRT error in swift after a button is pressed - the segue doesn't execute

I'm trying to make a leaderboard for a word scrambler app so I am saving the data before segueing to the next view controller which will eventually be a leaderboard. My outlets are all connected and the segue identifier was written correctly so I don't see why the app crashes after done is pressed
the error line occurs here: class AppDelegate: UIResponder, UIApplicationDelegate {
var finalScore = Int()
var playerName = String()
var allMyStoredData = UserDefaults.standard
class secondVC: UIViewController {
#IBOutlet weak var scoreLabel: UILabel!
#IBOutlet weak var nameTF: UITextField!
#IBOutlet weak var doneButton: UIButton!
var playerScore = 0
override func viewDidLoad() {
super.viewDidLoad()
scoreLabel.text = "Your score is: \(finalScore)"
loadData()
}
#IBAction func donePressed(_ sender: Any) {
saveData()
//this part won't execute
performSegue(withIdentifier: "toLeaderboard", sender: self)
}
func saveData () {
playerName = nameTF.text!
playerScore = finalScore
allMyStoredData.set(playerName, forKey: "saveTheName")
allMyStoredData.set(playerScore, forKey: "saveTheScore")
}
func loadData () {
if let loadPlayerName:String = UserDefaults.standard.value(forKey: "saveTheName") as? String {
playerName = loadPlayerName
}
if let loadTheScore:Int = UserDefaults.standard.value(forKey: "saveTheName") as? Int {
playerScore = loadTheScore
}
}
}
Update: there was an outlet in the view controller the segue "toLeaderboard" goes to which wasn't connected or used so I deleted it and now the code is fine

data not showing up in firebase database

im attempting to add user data via a create account view controller which contains all UITextFields (password, confirm password, first name, last name, phone number). when the create account button is tapped, the users email shows up in the authentication section on the firebase website but the user information from the first name, last name and phone number text fields are not passed into the database. I'm new to iOS development and have never used firebase so im unsure what the issue is. the app runs without crashing.
below is my Create Account view controller
thanks in advance
import UIKit
import FirebaseAuth
import QuartzCore
import FirebaseDatabase
import Firebase
class CreateAccount: UIViewController {
var refUsers: DatabaseReference!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var confirmPasswordTextField: UITextField!
#IBOutlet weak var firstNameTextField: UITextField!
#IBOutlet weak var lastNameTextField: UITextField!
#IBOutlet weak var phoneNumberTextField: UITextField!
#IBOutlet weak var alreadyHaveAccountLabel: UILabel!
#IBAction func loginButtonTapped(_ sender: Any) {
performSegue(withIdentifier: "showLoginScreen", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
self.refUsers = Database.database().reference().child("Users");
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
if Auth.auth().currentUser != nil {
print("success")
self.presentMainScreen()
}
}
#IBAction func createAccountTapped(_ sender: Any) {
if let email = emailTextField.text, let password = passwordTextField.text {
Auth.auth().createUser(withEmail: email, password: password, completion:{ user, error in
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
} else {
self.addUser()
print("this is the first name:", self.firstNameTextField.text!)
print("this is the last name:", self.lastNameTextField.text!)
print("this is the phone number" , self.phoneNumberTextField.text!)
print("success")
self.presentMainScreen()
}
})
}
}
func addUser(){
let key = refUsers.childByAutoId().key
let user = ["id":key,
"FirstName":firstNameTextField.text! as String,
"LastName":lastNameTextField.text! as String,
"PhoneNumber":phoneNumberTextField.text! as String
]
refUsers.child(key).setValue(user)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// 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.
}
*/
func presentMainScreen(){
let mainstoryboard = UIStoryboard(name: "Main", bundle: nil)
let mainTabController = mainstoryboard.instantiateViewController(withIdentifier: "MainTabController") as! MainTabController
mainTabController.selectedViewController = mainTabController.viewControllers?[0]
self.present(mainTabController, animated: true, completion: nil)
//let storyboard:UIStoryboard = UIStoryboard(name:"Main", bundle:nil)
//let loggedInVC:LoggedInVC = storyboard.instantiateViewController(withIdentifier: "LoggedInVC") as! LoggedInVC
//self.present(loggedInVC, animated: true, completion: nil)
}
}
Try this:
Instead of set value use update value
let childUpdates = ["/user/\(key)": user]
refUser.updateChildValues(childUpdates)
Hope this helps :)

Unresolved identifier using segue when passing data

In my app I am using segue to pass data between two viewcontrollers and that should be easy enough, but for som reason I can`t see there I keep getting "Unresolved Identifier"
Her are some of the code that has to do with that function.
from ViewController 1
import UIKit
import CoreData
class ViewController: UIViewController, UITextFieldDelegate
{
#IBOutlet var panelWidthTextField: UITextField!
#IBOutlet var panelHightTextField: UITextField!
#IBOutlet var panelsWideTextField: UITextField!
#IBOutlet var panelsHightTextField: UITextField!
#IBOutlet var panelPitchTextField: UITextField!
#IBOutlet var calculateButton: UIButton!
#IBOutlet var resultWithLabel: UILabel!
#IBOutlet var resultHightLabel: UILabel!
#IBOutlet var fillAllFieldsLabel: UILabel!
var pawidth:String!
var pahight:String!
var papitch:String!
override func viewDidLoad()
{
super.viewDidLoad()
panelWidthTextField.text = pawidth
panelHightTextField.text = pahight
panelPitchTextField.text = pap itch
From Second ViewController
import UIKit
import CoreData
class DataBase: UIViewController, UITextFieldDelegate
{
#IBOutlet var makerTextField: UITextField!
#IBOutlet var modelTextField: UITextField!
#IBOutlet var stPanelWidthTextField: UITextField!
#IBOutlet var stPanelHightTextField: UITextField!
#IBOutlet var stPitchTextField: UITextField!
let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
// Removes keyboard when touch outside edit field.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
view.endEditing(true)
super.touchesBegan(touches, withEvent: event)
}
#IBAction func saveButton(sender: UIButton)
{
let ed = NSEntityDescription.entityForName("Ledinfo", inManagedObjectContext: moc)
let model = Ledinfo(entity:ed!, insertIntoManagedObjectContext:moc)
model.manufactor = makerTextField.text
model.model = modelTextField.text
model.panelwidth = stPanelWidthTextField.text
model.panelhight = stPanelHightTextField.text
model.pitch = stPitchTextField.text
do {
try moc.save()
makerTextField.text = ""
modelTextField.text = ""
stPanelWidthTextField.text = ""
stPanelHightTextField.text = ""
stPitchTextField.text = ""
Alert.show("Succsess", message: "Your Record Is Saved", vc: self)
}
catch _ as NSError
{
Alert.show("Failed", message: "Something Went Wrong", vc: self)
}
}
#IBAction func searchButton(sender: UIButton)
{
let ed = NSEntityDescription.entityForName("Ledinfo", inManagedObjectContext: moc)
let req = NSFetchRequest()
req.entity = ed
let cond = NSPredicate(format: "manufactor = %#", makerTextField.text!)
req.predicate = cond
do {
let result = try moc.executeFetchRequest(req)
if result.count > 0
{
let model = result[0] as! Ledinfo
makerTextField.text = model.manufactor
modelTextField.text = model.model
stPanelWidthTextField.text = model.panelwidth
stPanelHightTextField.text = model.panelhight
stPitchTextField.text = model.pitch
} else
{
Alert.show("Failed", message: "No Record Is Found", vc: self)
}
} catch _ as NSError!
{
Alert.show("Failed", message: "No Record Is Found" , vc: self)
}
}
#IBAction func transfereButton(sender: UIButton) {
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "transfereButton") {
let svc = segue.destinationViewController as! ViewController
svc.pawidth = stPanelWidthTextField.text
svc.pahight = stPanelHightTextField.text
svc.papitch = stPitchTextField.text
}
}
}
It can not find panelWidthTextField.text, panelHightTextField.text and panelPitchTextField.text as identifier.
I have check spelling and just can`t seem to be able to find what is missing.
Any help is appreciated
"Segue" means, that in "prepareForSegue" method you set the property of ViewController to some data in your DataBase controller. In your example, this can be done like this:
svc.pawidth = someDataFromDataBaseWhichYouWantToPassToSecondVC
svc.pahight = someDataFromDataBaseWhichYouWantToPassToSecondVC
svc.papitch = someDataFromDataBaseWhichYouWantToPassToSecondVC
And then, you can manipulate this data from your ViewController class.
You mistake that you are not passing the data from one VC to another, instead of that you are trying to set the property of 1stVC to another property of 1stVC, and there is no segue needed.
This has nothing to do with segues. do you have 3 text fields in your DataBase class with names panelWidthTextField, panelHightTextField and panelPithcTextField? It's complaining about not being able to find those variables.
You should call the performSegueWithIdentifier("transfereButton", sender: nil) inside your transfereButton IBOutlet action to actually make the prepareForSegue to run.

Resources