Terminating app due to uncaught exception 'NSUnknownKeyException' when updating Firebase - swift

When creating a function to add a key-value pair in Firebase I get a crash with the following report
* Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]: this class is not key value coding-compliant for the key score.'
* First throw call stack:
(0x1dbd9a3a8 0x1daf9fd00 0x1dbcb36c8 0x1dc796054 0x1dc7ed2a0 0x1dc7070e0 0x102e58cc8 0x102e50640 0x102e4ed18 0x102e4f2c8 0x103f24214 0x103f13f84 0x1daf9b760 0x20906dbf0 0x208af1f94 0x208af22c8 0x208af12dc 0x2090a6a90 0x2090a7cc8 0x209086f50 0x209152150 0x20915490c 0x209154c7c 0x20914d9c4 0x1dbd2a444 0x1dbd2a3c0 0x1dbd29c7c 0x1dbd24950 0x1dbd24254 0x1ddf63d8c 0x20906c4c0 0x102f2befc 0x1db7e0fd8)
libc++abi.dylib: terminating with uncaught exception of type NSException
Message from debugger: failed to send the k packet
The layout of my database is as such:
I believe the problem is I'm calling it to the wrong path in my function.
My functions to update the "score" is :
func updateRecentScore(chatRoomId: String, score: Int) {
let date = dateFormatter().string(from: Date())
firebase.child(kRECENT).queryOrdered(byChild: kCHATROOMID).queryEqual(toValue: chatRoomId).observeSingleEvent(of: .value) { (snapshot) in
if snapshot.exists() {
for recent in ((snapshot.value as! NSDictionary).allValues as Array) {
updateRecentScoreItem(recent: recent as! NSDictionary, score: score)
}
}
}
}
func updateRecentScoreItem(recent: NSDictionary, score: Int) {
var score = recent[kSCORE] as! Int
let values = [kSCORE: score] as [String: Any]
firebase.child(kRECENT).child((recent[kRECENTID] as? String)!).updateChildValues(values as [NSObject : AnyObject]) {
(error, ref) -> Void in
if error != nil {
ProgressHUD.showError("Couldnt update recent: \(error!.localizedDescription)")
}
}
}
I call the function to update it here:
let score = recentsRef.child(kRECENTID).value(forKey: kSCORE) as? Int
let newScore = score! + 1
let score1 = firebase.child(kRECENT).queryOrdered(byChild: kCHATROOMID).queryEqual(toValue: chatRoomId).value(forKey: kSCORE) as? Int
let newScore1 = score1! + 1
updateRecentScore(chatRoomId: chatRoomId, score: newScore1)
All help is appreciated as I'm not sure what to do to fix this and I have tried to look everywhere for an answer. If you need any further information please ask.

I think you're looking for this:
func updateRecentScore(chatRoomId: String, score: Int) {
let date = dateFormatter().string(from: Date())
firebase.child(kRECENT).queryOrdered(byChild: kCHATROOMID).queryEqual(toValue: chatRoomId).observeSingleEvent(of: .value) { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
for child in snapshots {
child.ref.child(kSCORE).setValue(score+1)
}
}
}
}
The main differences:
I loop over the child nodes with the built-in children property, which means I get a Snapshot, which allows me to simply look up the ref of each child.
I call setValue() directly on the score property, since you're only updating that property. Using updateChildValues is really only useful if you want to update multiple-but-not-all properties in one go.

Related

WKInterfaceTable is not getting populated with Codable data

My JSON object is not getting sent to my WKInterfaceTable.
UITableView is populating correctly. Last step is to populate the WKInterfaceTable. The code is not throwing an errors in Xcode but there is a runtime crash because the cast is failing.
Edit: Thanks to Dale I fixed an error handling line so the run-time message is gone, but the same problem persists.
printing loadedData: Optional(<5b7b2273 7065616b 6572223a 224a6f68 6e222c22 7469746c 65223a22 486f7720 61726520 796f753f 222c2274 6f223a22 323a3030 222c2266 726f6d22 3a22313a 3030227d ...>)
override func willActivate() {
super.willActivate()
if(WCSession.default.isReachable) {
let message = ["getMsgData" : [:]]
WCSession.default.sendMessage(message, replyHandler:
{ (result) -> Void in
print("Requesting data from phone")
print("printing message: \(message)")
print("printing messageObjects: \(self.messageObjects)")
if result["messageData"] != nil {
let loadedData = result["messageData"]
NSKeyedUnarchiver.setClass(MessageObject.self, forClassName: "MessageObject")
do {
let loadedPerson = try? JSONDecoder().decode(MessageObject.self, from: loadedData as! Data)
self.messageObjects = [loadedPerson]
self.progTable.setNumberOfRows(self.messageObjects.count, withRowType: "MsgRowController")
//code...
}
Through the process of updating to using the Codable protocol I didn't realize I had to remove previous instances of NSKeyedArchiver/Unarchiver.

Ignore records in FirebaseDB with swift

Im working on a swift app that displays records from firebase to a table view controller.
I have successfully been pulling in all data, But I have since added another field to the DB called "secretKey".. This doesn't not need to be used on the table view as its used elsewhere in the app
But now each time I try to run the app I get the following errors
2018-05-07 12:24:24.616490+0100 Loop Guardian[21847:9857567] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<NSTaggedPointerString 0xa030818c015ea1f9> valueForUndefinedKey:]: this class is not key value coding-compliant for the key createdAt.'
*** First throw call stack:
(0x18204b164 0x181294528 0x18204ae2c 0x1829fe434 0x182944e20 0x182944874 0x18297d930 0x1030084b0 0x103008740 0x1030f2840 0x1044892cc 0x10448928c 0x10448dea0 0x181ff3344 0x181ff0f20 0x181f10c58 0x183dbcf84 0x18b6695c4 0x10301de44 0x181a3056c)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
This only happens when the secretKey is present in the DB.. If I remove it the app works fine.
I somehow need to ignore this field
Heres the code used to pull the records from the DB
func observeMessages() {
let key = UserDefaults.standard.value(forKey: "uid") as! String
DBrefs.databaseMessages.child(key).observe(.value, with: { (snapshot) in
if snapshot.exists() {
let messageData = snapshot.value as! Dictionary<String, AnyObject>
self.dataArr = []
for (key,data) in messageData {
self.dataArr.append(data)
}
//THIS IS WHERE THE ERROR IS THROWN.. THREAD 1: SIGNAL SIGABRT
self.dataArr = (self.dataArr as NSArray).sortedArray(using: [NSSortDescriptor(key: "createdAt", ascending: true)]) as [AnyObject]
self.tblMessage.reloadData()
}
else {
}
})
}
Any help is appreciated
Thanks
Oliver
for (key,data) in messageData {
if (key == "secreyKey") {
continue;
}
self.dataArr.append(data)
}
Also use Swift method to sort the Array. Don't use NSArray use Array instead.
Like below code:
self.dataArr.sorted(by: {$0["createdAt"] as? Int64 ?? 0 < $1["createdAt"] as? Int64 ?? 0})

How to delete from Firebase database

Hi i have followed this tutorial: https://www.youtube.com/watch?v=XIQsQ2injLo
This explains how to save and retrieve from the database, but not how to delete. I am wondering how to delete the database node that belongs to the cell that is being deleted. Thanks
Edit. Code updated for Swift 3 and Swift 4.
I'm always using the remove with completion handler:
static let ref = Database.database().reference()
static func remove(child: String) {
let ref = self.ref.child(child)
ref.removeValue { error, _ in
print(error)
}
}
So for example if I want to delete the following value:
I call my function: remove(child: "mixcloudLinks")
If I want to go deeper and delete for example "added":
I need to change the function a little bit.
static func remove(parentA: String, parentB: String, child: String) {
self.ref.child("mixcloudLinks").child(parentA).child(parentB).child(child)
ref.removeValue { error, _ in
print(error)
}
}
Called like:
let parentA = "DDD30E1E-8478-AA4E-FF79-1A2371B70700"
let parentB = "-KSCRJGNPZrTYpjpZIRC"
let child = "added"
remove(parentA: parentA, parentB: parentB, child: child)
This would delete just the key/value "added"
EDIT
In case of autoID, you need to save the autoID into your Dictionary to be able to use it later.
This is for example one of my functions:
func store(item: MyClassObject) {
var item = item.toJson()
let ref = self.ref.child("MyParentFolder").childByAutoId()
item["uuid"] = ref.key // here I'm saving the autoID key into the dictionary to be able to delete this item later
ref.setValue(item) { error, _ in
if let error = error {
print(error)
}
}
}
Because then I'm having the autoID as part of my dictionary and am able to delete it later:
Then I can use it like .child(MyClassObject.uuid).remove... which is then the automatic generated id.
we can store the randomly generated id as the user id in the database and retrieve that to delete
for e.g. :
let key = ref?.childByAutoId().key
let post = ["uid": key,
"name": myName,
"task": myTask]
ref?.child(key!).setValue(post)
in order to delete
setvalue of the id as nil
for e.g. :
var key = [string]()
ref?.child(key[indexPath.row]).setValue(nil)
key.remove(at: indexPath.row)
myArray.remove(at: indexPath.row)
myTable.reloadData()

What am I doing wrong downloading data from parse?

I am trying to download some data from parse but I get an error message saying "Value of type 'PFObject' has no member 'name' What am I doing wrong?
here is my parse dashboard screenshot
here is my code to upload the data to parse:
var coordinates = PFGeoPoint (latitude: (newCoordinate2.latitude), longitude:(newCoordinate2.longitude))
var aboutSpot = PFObject(className: "spotdetail")
aboutSpot ["PFGeoPoint"] = coordinates
aboutSpot["name"] = "name"
aboutSpot.saveInBackgroundWithBlock { (succes, error) -> Void in
print("separate name and geopoint have been saved")
}
and here is my code to download my data:
var query = PFObject.query()
query!.findObjectsInBackgroundWithBlock ({ (objects, error) in
if let places1 = objects {
for object in places1 {
if let spotdetail = object as? PFObject {
self.rideSpots.append(spotdetail.name!)
}
}
}
print(self.rideSpots)
})
also not that on the line that says
if let spotdetail = object as? PFObject {
I get a warning saying "conditional cast from 'PFObject' to 'PFObject' always succeeds
I can probably solve this pretty easily but I wanted to mention it in case it could help solve the issue

Exception throw for null data with optional Int type in Realm

I am taking my first foray into using Realm (0.98.1 via Cocoapods, Xcode 7.2) and am running into a small problem that I am not sure how to solve.
I have a model class called Airport that declares a property
let elevationFt = RealmOptional<Int>()
I am creating a set of Airport objects and persisting them in the following way
public func cacheDataToPersistanceStore(data:NSArray) -> Bool {
var success = true
autoreleasepool {
do {
let realm = try Realm()
realm.beginWrite()
for object in data {
guard let dictionaryValues = object as? Dictionary<String, AnyObject> else {
debugPrint("Unable to convert data to correct type")
success = false
return
}
if(dictionaryValues["airportID"] as! Int == 6605) {
realm.create(Airport.self, value: dictionaryValues, update: true)
}
}
try realm.commitWrite()
}
catch(let e) {
debugPrint(e)
success = false
}
}
return success
}
For the airport entry in question, the dictionary that stores the relevant data looks to have a null value for the key "elevationFt", so I assume things will be OK for the optional Int property
Here is a string version of the dictionary:
["gps_code": 01MD, "ident": 01MD, "iata_code": , "local_code": 01MD, "keywords": , "elevationFt": , "type": seaplane_base, "municipality": Annapolis, "iso_country": US, "airportID": 6605, "longitudeDeg": -76.45600128173828, "latitudeDeg": 38.99919891357422, "iso_region": US-MD, "wikipedia_link": , "name": Annapolis Seaplane Base, "scheduled_service": no, "continent": NA, "home_link": ]
However once the create function starts for this set of data, an exception is thrown:
Terminating app due to uncaught exception 'RLMException', reason: 'Invalid value '' for property 'elevationFt''
I am guessing I have something set up incorrectly, but I am not quite sure how to fix this other than to clean my source data for that particular field.
The screenshot from the debugger shows that elevationFt is an empty string, which is not a number or null, so it is not a valid value for an optional int property.