App Crashes When Trying to Append Data to a Child Value

App crashes when trying to append data to a child value

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

App crashes before Firebase data is loaded when going back 1 screen

Maybe you could try running the following, and comment the output:

import UIKit
import Firebase

class FirebaseTableViewController: UITableViewController {

lazy var ref: DatabaseReference = Database.database().reference()
var chatMessageArray: Array<ChatMessage> = []
var messageRef: DatabaseReference!
var titleString = "" //TODO: Update this
var chatTable: UITableView = UITableView() //TODO: Update this



override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}

override func viewDidLoad() {
super.viewDidLoad()
print(titleString) // TODO: Check that it dose not contain: '.' '#' '$' '[' or ']''
messageRef = ref.child("locations").child(titleString)
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
chatMessageArray.removeAll()
messageRef.observe(.childAdded) { (snapshot) in
self.createMessage(snapshot:snapshot)
}
}

override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)

// removeAllObservers: Removes all observers at the current reference, but does not remove any observers at child references
messageRef.removeAllObservers()
}

func chatRoomScrollToBottom(animated: Bool) {

}

func createMessage(snapshot: DataSnapshot) {
guard let snapshotValue = snapshot.value as? Dictionary<String,String> else {
print("Error with snapshotValue")
return
}
guard let text = snapshotValue["message"],
let sender = snapshotValue["username"],
let img = snapshotValue["userImage"],
let upvote = snapshotValue["upvote"],
let timestamp = snapshotValue["timestamp"] else {
print("Error with snapshotValue[''] values")
return
}
let message = ChatMessage()
message.msgTimestamp = timestamp
message.messageBody = text
message.sender = sender
message.chatImageURL = img
guard let upvoteInt = Int(upvote) else {
print ("Error with pvoteInt")
return
}
message.upvoteString = String(upvoteInt)
self.chatMessageArray.append(message)
self.chatTable.reloadData()
self.chatRoomScrollToBottom(animated: true)
}

}

Hope it helps!

Child Updated crashing table (indexPath is out of range error that crashes my app Error)

This answer is going to require a little set up and restatement of the goal

The goal is to have two arrays, used as dataSources for two
tableViews. One array contains user type: macro and the other array
contains user type: micro.

If a user type is changed from macro to micro (and vice-versa) the OP
wants to remove the user from one table and add it to the other.

the conceptual answer is: add an observer to the users node in Firebase and when a change occurs to a user, see if it's the type property, and if so remove from one table and add it to another.

There are lots of solutions but let me present this very long-winded answer which could be reduced in both code and by property observers.

Start with three arrays, one to hold all users and the others to hold macro and micro users. Assume the UserClass has a String type property of either macro or micro

var allUsersArray = [UserClass]()
var macroArray = [UserClass]()
var microArray = [UserClass]()

Read in all users and then from that, divide the users into their respective type

...read firebase single event of .value, with: { snapshot in
and populate allUsersArray from the snapshot..
self.macroArray = self.allUsersArray.filter { $0.type == "macro" }
self.microArray = self.allUsersArray.filter { $0.type == "micro" }
self.observeChangeInUserProperty()
}

The below code adds an observer to the users array which will notify the app when any property of a user changes, and presents that user node in the snapshot.

func observeChangeInUserProperty() {
let ref = self.ref.child("users")
ref.observe(.childChanged, with: { snapshot in
let key = snapshot.key
let type = snapshot.childSnapshot(forPath: "type").value as! String // ! = never optional
//get the user from the allUsersArray by its key
if let user = self.allUsersArray.first(where: { $0.key == key }) {
if user.type != type { //if the type changed, handle it
user.type = type //update the allUsersArray
if type == "macro" { //if the new type is macro remove the user from the micro array
if let userIndex = self.microArray.firstIndex(where: { $0.key == key }) {
self.microArray.remove(at: userIndex)
self.macroArray.append(user) //add user to macro array
}
} else { //new type is micro so remove from macro array
if let userIndex = self.macroArray.firstIndex(where: { $0.key == key }) {
self.macroArray.remove(at: userIndex)
self.microArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.microTable.reloadData()
self.mactoTable.reloadData()
}
}
})
}

As mentioned this is a lot of extraneous code and could be condensed with property observers or leveraging a single array for both tables or a number of other solutions.

Edit

In case you want to know how to populate the all users array from Firebase, you need to have a User class that is init'ed from a snapshot and here's the code

func loadAllUsersAndPopulateArray() {
let ref = self.ref.child("users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = UserClass(withSnap: userSnap)
self.allUsersArray.append(user)
}
})
}

App Crashes Due to Binding to Table Cell View

Cocoa Bindings uses Key Value Observing (KVO) and the observed object must be KVO compatible. See Using Key-Value Observing in Swift.

You can only use key-value observing with classes that inherit from NSObject.

Mark properties that you want to observe through key-value observing with both the @objc attribute and the dynamic modifier.

Solution A: Return a KVO compatble object from outlineView(_:objectValueFor:byItem:)

Solution B: Don't use Cocoa Bindings. Create a subclass of NSTableCellView and add a enabledCheckbox outlet. Set the values in outlineView(_:viewFor:item:).

Firebase Swift 3 Database crashes on setValue withCompletionBlock

tl;dr: Firebase provides a setValue(_ value: Any?, andPriority priority: Any?) which is incorrectly matched when using a trailing closure with setValue(_ value: Any?, withCompletionBlock: (Error?, FIRDatabaseReference) -> Void).

Solution: When using an API that has many varieties, avoid using trailing closures. In this case, prefer setValue(myValue, withCompletionBlock: { (error, dbref) in /* ... */ }); do not use setValue(myValue) { (error, dbref) in /* ... */ }.

Explanation

This appears to be a Swift bug. As in other languages, such as Java, Swift generally chooses the most specific overload. E.g.,

class Alpha {}
class Beta : Alpha {}

class Charlie {
func charlie(a: Alpha) {
print("\(#function)Alpha")
}
func charlie(a: Beta) {
print("\(#function)Beta")
}
}

Charlie().charlie(a: Alpha()) // outputs: charlie(a:)Alpha
Charlie().charlie(a: Beta() as Alpha) // outputs: charlie(a:)Alpha
Charlie().charlie(a: Beta()) // outputs: charlie(a:)Beta

However, when overloaded functions match a trailing closure, Swift (at least, sometimes) selects the more general type. E.g.,

class Foo {
func foo(completion: () -> Void) {
print(#function)
}
func foo(any: Any?) {
print(#function)
}
}

func bar() {}
Foo().foo(completion: bar) // outputs: foo(completion:)
Foo().foo(any: bar) // outputs: foo(any:)
Foo().foo() { () in } // outputs: foo(any:)
// ^---- Here lies the problem
// Foo().foo(bar) will not compile; can't choose between overrides.

Any? is a more general type than () -> Void -- i.e., "anything, even null" is more broad than "a function receiving 0 parameters and returning something of type Void". However, the trailing closure matches Any?; this is the opposite of what you would expect from a language that matches the most specific type.

Pausing an observeEventType Firebase

Alright, so what I ended up doing was writing a simple if statement, catching if the null existed.

if let data =  snapshot.value! as? [String: AnyObject] {
for (key, value) in data {
print("\(key) -> \(value["name"]!)")
dataArray.append(key)
locArray.append(value["location"] as! String)
nameArray.append(value["name"] as! String)
totalArray.append(value["total"] as! Int)
}}

It's a workaround when the null error comes up.

Firebase Unique Identifier (user id) not being recognized and app crashes when trying to access Database? Swift iOS9

The problem was the in the SignUp vc in which I didn't include on this page. @Justin Doan figured it out. On the SignUp vc I had set one of the class's properties to

//SignUpController Property
let userID = FIRAuth.auth()?.currentUser?.uid

On the signUpButton action I had

FIRAuth.auth()?.createUserWithEmail(self.emailTextField.text!, password: self.passwordTextField.text!, completion: {

(user, error) in

When you create a new account using this method, user (from user, error) is the newly created user with a uid which you can access via user!uid. The userID property and this uid had 2 different values. To fix it I had to get rid of the property from the top of the class and move it within the FIRAuth.auth()?.createUserWithEmail completion block like so:

FIRAuth.auth()?.createUserWithEmail(self.emailTextField.text!, password: self.passwordTextField.text!, completion: {

(user, error) in

//The property should be removed from the top of the class to here
let userID = FIRAuth.auth()?.currentUser?.uid

//This should always print a successful match
if user!.uid != currentUserID{
print("\nYOUR USER ID'S DON'T MATCH")
}else{
print("\nTHE USER ID'S SUCCESSFULLY MATCH")
}

The SignUpController code, question, and answer is here: Firebase issuing out 2 different uid's -Swift iOS

Hope this helps someone!



Related Topics



Leave a reply



Submit