Saving UITextView Text to Parse - swift

I was wondering how to save the text inside UITextView to parse. Everytime I run my code below an error comes up saying it accidentally "found nil when unwrapping an optional" on the lines that save the information to parse.
Note: The functions "SaveNotesParse" and "SaveFrontScreenInfo" are where the errors occur. They are also both called in another class.
#IBOutlet weak var titleText: UITextView!
#IBOutlet weak var descriptionText: UITextView!
#IBOutlet weak var titleText2: UITextView!
#IBOutlet weak var contentText: UITextView!
let testObject = PFObject(className: "Notes")
func SaveNotesParse () {
//parse stuff
testObject["Title2"] = titleText2.text
testObject["Content"] = contentText.text
print("Saving")
testObject.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
print("Object has been saved.")
}
}
func SaveFrontScreenInfo () {
testObject["Title"] = titleText.text
testObject["Description"] = descriptionText.text
}
override func awakeFromNib() {
foregroundView.layer.cornerRadius = 10
foregroundView.layer.masksToBounds = true
super.awakeFromNib()
}
override func animationDuration(itemIndex:NSInteger, type:AnimationType)-> NSTimeInterval {
let durations = [0.26, 0.2, 0.2]
return durations[itemIndex]
}
Image of the error and line that it appears:
Line that the error message appears
The actual error message as shown in the logs

Try using the setObject function like so:
testObject.setObject(titleText2.text, forKey: "Title2")
Otherwise, can you tell us what is nil? It will have to be either the testObject or the Text Fields. Try printing them to see which one is nil.

Related

How can I show the localized description of an error in an error label format to a user in Swift?

I'm very new to Swift, and Instead of just printing the localized description of an error when a user attempts to register for an app, I want to show it in an error label to the user. However, I get the error "Expression is not assignable: function call returns immutable value." I'm not sure what this means or what I should be doing differently in order to show the default description for the error.
class RegisterViewController: UIViewController {
#IBOutlet weak var emailTextfield: UITextField!
#IBOutlet weak var passwordTextfield: UITextField!
#IBOutlet weak var errorLabel: UILabel!
override func viewDidLoad() {
errorLabel.isHidden = true
}
#IBAction func registerPressed(_ sender: UIButton) {
if let email = emailTextfield.text, let password = passwordTextfield.text {
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
if let e = error {
self.errorLabel.isHidden = false
String(e.localizedDescription) = self.errorLabel.text!
"Expression is not assignable: function call returns immutable value"
} else {
//Navigate to ChatViewController
self.performSegue(withIdentifier: "RegisterToChat", sender: self)
}
}
}
}
}
The assignment must be the other way round. You are going to assign always the right side to the left side.
And you don’t need to create a string from a string
self.errorLabel.text = e.localizedDescription

Fetch Data From Firestore for User Profile (swift, iOS, Xcode, firebase/firestore)

I'm a bit of a newb here, so please be kind. I'm a former Air Force pilot and am currently in law school, so coding is not my full time gig...but I'm trying to learn as I go (as well as help my kiddos learn).
I'm working on a profile page for my iOS app. I've gone through the firebase documentation quite extensively, but it just doesn't detail what I'm trying to do here. I've also searched on this site trying to find an answer...I found something that really helped, but I feel like something is just not quite right. I posted this previously, but I deleted because I did not receive any helpful input.
What I'm trying to do is display the user's data (first name, last name, phone, address, etc.) via labels. The code (provided below) works to show the user id and email...I'm thinking this is because it is pulled from the authentication, and not from the "users" collection. This code is attempting to pull the rest of the user's data from their respective document in the users collection.
Here is the full code for the viewController. I've tried and failed at this so many times that I'm really on my last straw...hard stuck! Please help!
My guess is that something is not right with the firstName variable...whether that be something wrong with the preceding database snapshot, or with the actual coding of the variable. But then again...I don't know what I'm doing...so perhaps I'm way off on what the issue is.
// ClientDataViewController.swift
import UIKit
import Firebase
import FirebaseAuth
import FirebaseFirestore
class ClientDataViewController: UIViewController {
#IBOutlet weak var firstNameLabel: UILabel!
#IBOutlet weak var lastNameLabel: UILabel!
#IBOutlet weak var emailLabel: UILabel!
#IBOutlet weak var phoneLabel: UILabel!
#IBOutlet weak var streetLabel: UILabel!
#IBOutlet weak var street2Label: UILabel!
#IBOutlet weak var cityLabel: UILabel!
#IBOutlet weak var stateLabel: UILabel!
#IBOutlet weak var zipLabel: UILabel!
#IBOutlet weak var attorneyLabel: UILabel!
#IBOutlet weak var updateButton: UIButton!
#IBOutlet weak var passwordButton: UIButton!
#IBOutlet weak var uidLabel: UILabel!
let id = Auth.auth().currentUser!.uid
let email = Auth.auth().currentUser!.email
// MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.uidLabel.text = id
self.emailLabel.text = email
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) // call super
getName { (name) in
if let name = name {
self.firstNameLabel.text = name
print("great success")
}
}
}
// MARK: Methods
func getName(completion: #escaping (_ name: String?) -> Void) {
let uid = "dL27eCBT70C4hURGqV7P"
let docRef = Firestore.firestore().collection("users").document(uid)
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
print("Document data: \(dataDescription)")
} else {
print("Document does not exist")
}
completion("put the first name data here after we figure out what's in the doc")
}
}
}
The following with solve your problems. However, I'd advise against declaring id and email as force-unwrapped instance properties; they don't even need to be instance properties, let alone force unwrapped. Always safely unwrap optionals before using their values, especially these authorization properties because if the user isn't signed in or is signed out underneath you (expired token, for example), the app would crash here and, as with flying planes, crashing is always to be avoided.
class ClientDataViewController: UIViewController {
#IBOutlet weak var firstNameLabel: UILabel!
#IBOutlet weak var lastNameLabel: UILabel!
#IBOutlet weak var emailLabel: UILabel!
#IBOutlet weak var phoneLabel: UILabel!
#IBOutlet weak var streetLabel: UILabel!
#IBOutlet weak var cityLabel: UILabel!
#IBOutlet weak var stateLabel: UILabel!
#IBOutlet weak var zipLabel: UILabel!
#IBOutlet weak var attorneyLabel: UILabel!
#IBOutlet weak var updateButton: UIButton!
#IBOutlet weak var passwordButton: UIButton!
#IBOutlet weak var uidLabel: UILabel!
let id = Auth.auth().currentUser!.uid
let email = Auth.auth().currentUser!.email
// MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.uidLabel.text = id
self.emailLabel.text = email
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) // call super
getName { (name) in
if let name = name {
self.firstNameLabel.text = name
print("great success")
}
}
}
// MARK: Methods
func getName(completion: #escaping (_ name: String?) -> Void) {
guard let uid = Auth.auth().currentUser?.uid else { // safely unwrap the uid; avoid force unwrapping with !
completion(nil) // user is not logged in; return nil
return
}
Firestore.firestore().collection("users").document(uid).getDocument { (docSnapshot, error) in
if let doc = docSnapshot {
if let name = doc.get("firstName") as? String {
completion(name) // success; return name
} else {
print("error getting field")
completion(nil) // error getting field; return nil
}
} else {
if let error = error {
print(error)
}
completion(nil) // error getting document; return nil
}
}
}
}
And thank you for your service! Hopefully you got to fly a B1-B.
I suspect from the evidence in your question that you are getting a doc, but have an incorrect field name or an uninitialized field in the retrieved doc. As a debug step, replace your getName function with this one, which prints all of the data found in the doc.
func getName(completion: #escaping (_ name: String?) -> Void) {
let uid = Auth.auth().currentUser!.uid
let docRef = Firestore.firestore().collection("users").document(uid)
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
print("Document data: \(dataDescription)")
} else {
print("Document does not exist")
}
completion("put the first name data here after we figure out what's in the doc")
}
}
Once we know what's in the doc, it should be easy to work out what value to pass to the completion function.

Error: "Cannot capture 'word' before it is declared" iOS swift

I'm writing code for a dictionary app in splitviewcontroller. I set a "Word" class with various entries, which are now not being read by the computer when I try to label them.
import UIKit
class DetailViewController: UIViewController {
class Word {
let name: String
let meaning: String
let numberOfTimesTapped: String
init(name: String, meaning: String, numberOfTimesTapped: String) {
self.name = name
self.meaning = meaning
self.numberOfTimesTapped = numberOfTimesTapped
}
}
#IBOutlet weak var WordLabel: UILabel!
#IBOutlet weak var DescriptionLabel: UILabel!
#IBOutlet weak var NumberOfTimesTappedLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
func refreshUI() {
loadViewIfNeeded()
WordLabel.text = word?.name //[THIS IS WHERE I GET THE ERROR: "Cannot capture 'word' before it is declared" ALTHOUGH IT'S BEEN CLEARLY DECLARED BEFORE!!!]
DescriptionLabel.text = word?.meaning
NumberOfTimesTappedLabel.text = word?.numberOfTimesTapped
}
var word: Word? {
didSet {
refreshUI()
}
}
You'd see it much easier if you were using proper indentation, but you declare var word inside of refreshUI. You need to declare it outside of that so that the scope is accessible inside of refreshUI. Also you declare refreshUI inside of viewDidLoad, which is most likely not what you want. A fixed version of this code would be
var word: Word? {
didSet {
refreshUI()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
func refreshUI() {
loadViewIfNeeded()
WordLabel.text = word?.name
DescriptionLabel.text = word?.meaning
NumberOfTimesTappedLabel.text = word?.numberOfTimesTapped
}

How to grab the value of a WebView in Swift

Suppose I have a label that is a NSTextField. I know I can access the value of that label by:
#IBOutlet weak var label: NSTextField!
let labelValue = label.stringValue
And then I can use that variable accordingly.
The same is easily said for an NSImage:
#IBOutlet weak var productImageView: NSImageView!
let img = productImageView.image
My question is how do I grab the value of a WebView. I am unsure which property allows me to use a WebView.
#IBOutlet weak var videoTemp: WebView!
let videoPassed = videoTemp //how do I access this videoTemp's value much like .stringValue and .image
I am trying to load dynamic video URL's to Youtube videos when I click on a collection view item. The line that I have commented in my setupAppVideo method is where my fatal error occurs:
"fatal error: unexpectedly found nil while unwrapping an Optional value"
but when I print out the url and request variables their are no nil values and all of them are the correct links in the console.
import Cocoa
import WebKit
class test1: NSCollectionViewItem {
#IBOutlet weak var label: NSTextField!
#IBOutlet weak var label2: NSTextField!
#IBOutlet weak var productImageView: NSImageView!
#IBOutlet weak var videoTemp: WKWebView!
var buildProduct: ProductModel? {
didSet{
label.stringValue = (buildProduct?.product_name)!
label2.stringValue = (buildProduct?.product_price)!
setupAppIconImage()
setupAppVideo()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
func setupAppIconImage() {
if let appIconImageURL = buildProduct?.product_image {
let url = NSURL(string: appIconImageURL)
URLSession.shared.dataTask(with: url! as URL,completionHandler:{(data, response, error) in
if error != nil {
print(error)
return
}
DispatchQueue.main.async(){
self.productImageView.image = NSImage(data: data!)
}
}).resume()
}
}
func setupAppVideo(){
if let appVideoURL = buildProduct?.product_video{
let url = NSURL(string: appVideoURL)
print(url)
let request = NSURLRequest(url: url as! URL)
print(request)
//self.videoTemp.load(request as URLRequest)
}
}
}

if statement returning a value not working for UiLabel

my fairly new to swift and programming, I'm trying to display a value from an if statement. Here is my func within my UiLabel. I've tried a few variations along the same lines but it only every returns "calculate.fuelTank" it never seems to trigger the second part to my IF statement?
#IBOutlet weak var startingFuelDisplay: UILabel! //not working yet
func refreshUiopeningFuel() {
if calculate.totalFuel <= Double(calculate.fuelTank) {
print (Double(calculate.fuelTank)) // FuelTank
} else {
print (calculate.totalFuel) // TotalFuel
}
Do I need to add a bool argument to trigger "else"? I have also tried using the "return" function with initialised string which included the value I was trying to extract, finally I need this to work for another display.
here is my full view controller code (i'm new I'm sure it could be cleaner)
import UIKit
class ViewController: UIViewController {
let calculate = Inputs ( raceLaps: 13, fuelRate: 3.7, fuelTank: 110, laptime: 85.456, tyreWear: 0.05 )
#IBOutlet weak var rate: UITextField!
#IBOutlet weak var laps: UITextField!
#IBOutlet weak var tank: UITextField!
#IBOutlet weak var tyreWear: UITextField!
#IBOutlet weak var laptime: UITextField!
#IBOutlet var cancelKeyboard: UITapGestureRecognizer!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//Looks for single or multiple taps.
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
view.addGestureRecognizer(tap)
}
//Calls this function when the tap is recognized.
func dismissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
refreshUiFuel()
refreshUiStops()
refreshUiTyreLife()
refreshUiTyreLifeLaps()
refreshUiopeningFuel()
refreshUiBoxOnLap ()
}
#IBAction func calculate(sender: UIButton) {
if let rateVal = Double(rate.text!),
tankVal = Int(tank.text!),
lapVal = Int(laps.text!),
wearVal = Double(tyreWear.text!),
laptimeVal: Float = 85.456 {
let fuelModel = Inputs(raceLaps: lapVal, fuelRate: rateVal, fuelTank: tankVal, laptime: laptimeVal, tyreWear: wearVal )
totalFuelDisplay.text = ("\(Double(fuelModel.totalFuel))")
totalStopsDisplay.text = ("\(Int(fuelModel.totalStops))")
tyreLifeDisplay.text = ("\(Int(fuelModel.tyreChangesRaceDistanceTotal))")
tyreLifeLapsDisplay.text = ("\(Int(fuelModel.tyreLife))")
startingFuelDisplay.text = ("\(refreshUiopeningFuel())")
}
else {
totalFuelDisplay.text = "missing value"
totalStopsDisplay.text = "missing value"
tyreLifeDisplay.text = "missing value"
tyreLifeLapsDisplay.text = "missing value"
startingFuelDisplay.text = "missing Value"
}
}
#IBOutlet weak var totalFuelDisplay: UILabel!
func refreshUiFuel()->String {
return totalFuelDisplay.text!
}
#IBOutlet weak var totalStopsDisplay: UILabel!
func refreshUiStops()->String {
return totalStopsDisplay.text!
}
#IBOutlet weak var tyreLifeDisplay: UILabel!
func refreshUiTyreLife()->String {
return tyreLifeDisplay.text!
}
#IBOutlet weak var tyreLifeLapsDisplay: UILabel!
func refreshUiTyreLifeLaps()->String {
return tyreLifeLapsDisplay.text!
}
#IBOutlet weak var pitOnLapDisplay: UILabel!
func refreshUiBoxOnLap () {
}
#IBOutlet weak var startingFuelDisplay: UILabel! //not working yet
func refreshUiopeningFuel() ->Double {
print(calculate.fuelTank)
print(calculate.totalFuel)
if calculate.totalFuel <= Double(calculate.fuelTank) {
return Double(calculate.fuelTank) // FuelTank
} else {
return calculate.totalFuel // TotalFuel
}
}
}
all helped welcomed
Judging from the natural real-world logic, it appears you've simply reversed the if/else logic. It would seem that if totalFuel is less than the tank's capacity (the if clause), you should return totalFuel in that case, and return the tank capacity in the else clause.