App crashes when trying to append data to a child value - swift

I'm following the instructions as shown in firebase but I'm still getting crashes even after making sure that the text entry is type String.
Here's the error:
Terminating app due to uncaught exception 'InvalidPathValidation', reason: '(child:) Must be a non-empty string and not contain '.' '#' '$' '[' or ']''
and here's the code:
import UIKit
import Firebase
import FirebaseDatabase
import FirebaseAuth
class BioEditViewController: UIViewController {
#IBOutlet weak var bioTextView: UITextView!
let databaseRef = FIRDatabase.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(animated: Bool) {
let userID = FIRAuth.auth()?.currentUser?.uid
databaseRef.child("users").child(userID!).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
// Get user level
let userBio = snapshot.value!["userBio"] as! String
self.bioTextView.text = userBio
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func doneSave(sender: UIButton) {
let textView = bioTextView.text
self.dismissViewControllerAnimated(false, completion: nil)
databaseRef.child("users/(user.uid)/userBio").setValue(textView)
}
}
I'm just trying to update a specific child: userBio and not affect the entire object.

Warning
Avoid instantiating your database reference to a variable out of scope. Reason why :- Outside your scope, when you instantiate a class to a variable you don't know wether or not your FIRApp has already been configured or not, or in general if that class has even been initialised as of yet or not. Just provide a reference(!) to the variable and instantiate later in a scope.
Change:-
let databaseRef = FIRDatabase.database().reference()
to
let databaseRef = FIRDatabaseReference!
And before using it just initialise it as:-
databaseRef = FIRDatabase.database().reference()
Try :-
#IBAction func doneSave(sender: UIButton) {
let textView = bioTextView.text
self.dismissViewControllerAnimated(false, completion: nil)
databaseRef = FIRDatabase.database().reference()
databaseRef.child("users/\(FIRAuth.auth!.currentUser!.uid)/userBio").setValue(textView)
}

Related

practicing Core Data in Swift save method creates new entry everytime

I've been trying to figure out how Core Data works with using Swift. I don't think I'm grasping the proper concept of the whole thing. I get that I need to be interacting with Context to store data to PersistentContainer, but it seems everytime I press on save button, the data is stored as brand new. I want it to be able to update the existing row. Below is my code. Any help will be greatly appreciated. Thank you.
import UIKit
import CoreData
class ViewController: UIViewController {
var editNotes: Note?
let dataFilePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func saveButton(_ sender: UIButton) {
print (dataFilePath)
print (sender.tag)
var new: Note?
if let note = editNotes {
new = note
} else {
new = Note(context: context)
}
new?.body = textView.text
new?.date = NSDate() as Date
do {
ad.saveContext()
self.dismiss(animated: true, completion: nil)
} catch {
print(“cannot save”)
}
}
}

How do I add data from a user in firebase rather than replace what is already there?

The app presents users with a random quote. I want users to be able to save the quotes and see which ones they saved. I can get a single quote to save, however, anytime the save button is clicked again, it overrides the previously saved quote with the new one. I've tried to find the answer elsewhere, but I cannot seem to get it to work. Below is my current code. I've also tried replacing setValue with updateChildValues, but I get the error Cannot convert value of type 'String' to expected argument type '[AnyHashable : Any]'.
import UIKit
import FirebaseDatabase
import FirebaseAuth
class QuotesViewController: UIViewController {
var ref: DatabaseReference?
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
}
#IBAction func backToMain(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(identifier: "mainHome")
vc.modalPresentationStyle = .overFullScreen
present(vc, animated: true)
}
#IBOutlet weak var quotesLabel: UILabel!
#IBAction func saveButton(_ sender: UIButton) {
guard let user = Auth.auth().currentUser?.uid else { return }
ref!.child("users").child(Auth.auth().currentUser!.uid).child("Quotes").child("quote").setValue(quotesLabel.text!)
}
#IBOutlet weak var nextButtonOutlet: UIButton!
#IBAction func nextQuoteButton(_ sender: UIButton) {
let quotesData = QuotesData()
let randomQuote = quotesData.randomQuote()
quotesLabel.text = randomQuote
}
}
I've also tried:
ref!.child("users").child(Auth.auth().currentUser!.uid).child("Quotes").child("quote").updateChildValues(quotesLabel.text!)
That is expected, you basically are referencing the very same node child("quote") and trying to change its value. But if you want to have multiple quotes, what you need to do is to create multiple nodes under the parent child("Quotes") with different names.
One trivial way of doing so, you might append a different number to each new quote node, for example when you want to add a new quote, define the following path:
child("Quotes").child("quote1").setValue("...")
Path for another quote:
child("Quotes").child("quote2").setValue("...")
And so on.
Alternatively, you can use Firebase Database reference method childByAutoId() to generate unique names. You will use that method after defining the parent node:
ref!.child("users").child(Auth.auth().currentUser!.uid).child("Quotes").childByAutoId().setValue(quotesLabel.text!)
Note:
Try to avoid force unwrapping as much as you can because that makes your app more prone to crashes.
I think you have to add one more field inside your firebase database that must be a unique one
For first time adding data into firebase you can write something like this
let key = ref.child("Quotes").childByAutoId().key
let dict = ["quote": quotesLabel.text!,
"quoteId" : key ?? ""
] as [String: Any]
And whenever you are saving the same quote then you can update the value inside the particular quoteID like this
func updateDatainFirebase(quoteId:String,quote:String){
let dict = ["quote": quotesLabel.text!,
"quoteId" : quoteId ?? ""
] as [String: Any]
self.ref.child(quoteId).updateChildValues(dict)
}

Giving Usernames to users with Firebase & Swift

I am a new to programming, and right now I want to give my users a username and then store it in the firebase real time database. However, every time I run my code it comes up with:
Thread 1: signal SIGABRT
I have checked all of my #IB buttons etc for clashes but there is nothing that I can find. I think I have written code that may be out dated so I am hoping someone can shed some light on my situation and help out!
I think there error is coming from here:
import UIKit
import Firebase
class HandlerViewController: UIViewController {
#IBOutlet weak var username: UITextField!
var user : AnyObject?
var ref = DatabaseReference()
override func viewDidLoad() {
super.viewDidLoad()
self.user = Auth.auth().currentUser
ref = Database.database().reference()
// Do any additional setup after loading the view.
}
#IBAction func joinHaps(_ sender: Any) {
ref.child("Usernames").childByAutoId().setValue(username)
self.performSegue(withIdentifier:"HomeScreenOne", sender: nil)
}
}
In your crash log saying 'InvalidFirebaseData', reason: '(setValue:) Cannot store object of type UITextField at,
In this line your getting error, because setValue can't accept UITextField as input.
Change your code to :
#IBAction func joinHaps(_ sender: Any) {
//username is UITextfield, you can fetch text from it using .text
ref.child("Usernames").childByAutoId().setValue(username.text ?? "")
self.performSegue(withIdentifier:"HomeScreenOne", sender: nil)
}

Fatal Error - Unexpectedly Found nil while unwrapping an Optional Value

I am trying to work on a chat application using swift and when I build and ran the project during the run when I try to go to the ChatVewController it shows this EXC Bad Instruction Error.
The console says
Fatal Error: Unexpectedly found nil while unwrapping an optional value.
Here is my code.
import UIKit
import Firebase
class SportsLogin: UIViewController {
// MARK: Properties
let ref: Firebase = Firebase(url: BASE_URL2)
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue(segue, sender: sender)
let navVC2 = segue.destinationViewController as! UINavigationController
let chatVC2 = navVC2.viewControllers.first as! SportsViewController
chatVC2.senderId = ref.authData.uid // Assign the local user’s ID to chatVc.senderId; this is the local ID that JSQMessagesViewController uses to coordinate messages.
chatVC2.senderDisplayName = "" // chatVc.senderDisplayName is set to empty string, since this is an anonymous chat room.
}
#IBAction func loginDidTouch(sender: AnyObject) {
ref.authAnonymouslyWithCompletionBlock { (error, authData) -> Void in
if error != nil { // Check for an authentication error.
print(error.description)
return
}
// Inside of the closure, trigger the segue to move to ChatViewController.
print(self.ref.authData)
self.performSegueWithIdentifier("SportChat", sender: self)
}
}
}
The Line with the error is
chatVC2.senderId = ref.authData.uid // Assign the local user’s ID to chatVc.senderId; this is the local ID that JSQMessagesViewController uses to coordinate messages.
Thanks!
What are the SportsViewController ? if SportViewController is delcare by yourself, you should have the member of variable is sendId, is class memeber and NSString type.

How to have persistence with NSUserDefault?

I wish to save a simple username via:
NSUserDefaults.standardUserDefaults().setObject("UncleRic", forKey:"username")
But when I return, particularly via re-activation of the app, I get nothing:
(lldb) po gUserDefault.objectForKey("username") as? String
nil
Here's the simple code:
import UIKit
let gUserDefault = NSUserDefaults.standardUserDefaults()
let userName = gUserDefault.objectForKey("username") as? String
let password = gUserDefault.objectForKey("password") as? String
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NSUserDefaults.standardUserDefaults().setObject("UncleRic", forKey:"username")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I want to be able to access the User Default's values from the AppDelegate as well as from a UIViewcontroller.
How can I make this thing persistent?
Change your code to gUserDefault.setObject... and when you're done saving, call gUserDefault.synchronize()