I have parsed the JSON data, now while setting the JSON to my NSDictionary there might be certain keys in the JSON that might not be present. I want to check if the key is present in the JSON parsed to me and if not, set blank field as value to the key in the `NSDictionary' object.
jsonData = ["id": ((json["idnumber"]) as? String!)!,
"Name": ((json["name"]) as? String!)!,
"Roll Number": ((json["rollnumber"]) as? String!)!,
"Class": ((json["class"]) as? String!)!,
"Marks": ((json["marks"]) as? String!)!,
"Gender": ((json["gender"]) as? String!)!]
So in the above case, the marks field may or may not be present in the JSON. I want to check this and assign respective value to the corresponding key in jsonData.
I tried using "??", but it takes lot of compilation time.
You can use if let or guard for conditional optional wrapping for that like this.
var jsonData = [String : String]
if let num = json["idnumber"]) as? String {
jsonData["id"] = num
}
else {
jsonData["id"] = num
}
and so on for others.
Edit: You can also try like this.
var id = name = rollNum = class = ""
if let num = json["idnumber"]) as? String {
id = num
}
if let sname = json["name"]) as? String {
name = sname
}
...
Then at last create Dictionary
var jsonData = ["id": id, "name": name, ...]
You can set the value if present otherwise blank string (""). This will prevent crash. Try below code:-
let idValue = dictionary["idnumber"] as? String ?? ""
let name = dictionary["name"] as? String ?? ""
let rollNumber = dictionary["rollnumber"] as? String ?? ""
let className = dictionary["class"] as? String ?? ""
let marks = dictionary["marks"] as? String ?? ""
let gender = dictionary["gender"] as? String ?? ""
let jsonDic : NSMutableDictionary = NSMutableDictionary()
jsonDic.setObject(idValue, forKey: "id")
jsonDic.setObject(name, forKey: "name")
jsonDic.setObject(className, forKey: "class")
jsonDic.setObject(rollNumber, forKey: "rollNumber")
jsonDic.setObject(marks, forKey: "marks")
jsonDic.setObject(gender, forKey: "gender")
Related
database structure
I am trying to get an array of users(strings) from a comment, but am having trouble since it is kinda deep in my database, here is the implementation I've tried, it is returning 0 for the count.
REF_FEEDMESSAGES.child(messageKey).child("comments").observeSingleEvent(of: .value) { (commentSnapshot) in
guard let commentSnapshot = commentSnapshot.children.allObjects as? [DataSnapshot] else {return}
for comment in commentSnapshot {
let theComment = comment.value as? [String: Any]
let theContent = theComment?["content"] as? String ?? ""
let theIcon = theComment?["icon"] as? String ?? ""
let theColor = theComment?["color"] as? String ?? ""
let theDate = theComment?["date"] as? String ?? "0"
let theName = theComment?["userName"] as? String ?? ""
let theVerified = theComment?["isVerified"] as? String ?? "no"
let profileImageURL = theComment?["profileImageURL"] as? String ?? ""
let postedBy = theComment?["postedBy"] as? String ?? ""
let likes = theComment?["likes"] as? String ?? ""
let key = comment.key
let likers = comment.childSnapshot(forPath: "likedBy").value as? [String] ?? []
print(likers.count)
guard let likers = comment.childSnapshot(forPath: "likedBy").children.allObjects as? [DataSnapshot] else {return}
for like in likers {
let theLike = like.value as? [String:Any]
print(theLike!["user"] as? String ?? "")
commentLiked.append(theLike!["user"] as? String ?? "")
}
So recently I switch from Xcode 9 to Xcode 10 for my iOS app development. the first thing I noticed that when I tried to print out a variable, the value is wrapped with optional, while in Xcode 9 it never happened. for example here is the code that I test.
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as! String
let parameters = ["branch_id": loginData.profile.branchId,
"version": "\(version).\(build)",
"os_name" : "ios",
"user_id" : loginData.uid]
print(parameters)
and the output was like :
["os_name": "ios",
"branch_id": Optional("2"), "version": "1.5.8.3",
"user_id": Optional("1141")]
I've tried to force unwrap the code with exclamation mark
"branch_id": loginData.profile.branchId!,
or even better with coalescing operator
"branch_id": loginData.profile.branchId ?? "0"
It works, but I have like, 30+ lines of code with the same problem, do I need to do it one by one? Or is there a way to change this behaviour?
FYI I'm using Swift 4 for my project.
Edit : FYI this was tested on iOS 12, while before in Xcode 9 was tested in iOS 11
Edit:
To answer matt comment asking info about where loginData.profile.branchId come from, here it is.
So, the data is fetched from data model, and I use this code to fetch it:
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "User")
let fetchResults = try context.fetch(request) as? [NSManagedObject]
let loginData = fetchResults![0]
let profile = loginData.value(forKey: "profile") as! NSManagedObject
self.profile = Profile()
self.profile.branchId = profile.value(forKey: "branchId") as? String
Use Optional Unwrapping with if-let statement
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "User")
if let fetchResults = try context.fetch(request) as? [NSManagedObject]{
let loginData = fetchResults[0]
let profile = loginData.value(forKey: "profile") as! NSManagedObject
self.profile = Profile()
if let branchId = profile.value(forKey: "branchId") as? String{
self.profile.branchId = branchId
}
}
if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String, let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String{
let branchId = loginData.profile.branchId ?? ""
let branchId = loginData.uid ?? ""
let parameters = ["branch_id": branchId,
"version": "\(version).\(build)",
"os_name" : "ios",
"user_id" : login_tty.uid]
print(parameters)
}
Never use force unwrapping, i mean ! directly, it may result in crash,
instead safely unwrap using if let and guard let
if you are printing an optional value Xcode prints the value warapped with the word optional("value").
if you want to avoid this you must upwarapped the value.
you have 3 ways to do that:
the careful way, use guard let or if let:
if let branchId = profile.value(forKey: "branchId") as? String {
//here branchId != nil
}
guard let branchId = profile.value(forKey: "branchId") as? String else { return }
the force unwarapped way:
let branchId = profile.value(forKey: "branchId") as! String
on that way, if the value is nil the app will crash so be careful
use default value:
let branchId = profile.value(forKey: "branchId") as? String ?? "default value"
I ended up using coalescing operator which is ?? "" and implemented it my code like:
var parameters = [String: Any]()
if loginData.profile != nil {
if loginData.profile.branchId != "" {
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as! String
parameters = ["branch_id": loginData.profile.branchId ?? "",
"version" : "\(version).\(build)",
"os_name" : "ios",
"user_id" : loginData.uid ?? ""
]
}
}
Please anyone who would show me how to include the snapshot key value along with children value that I already append to my array (forgot to include it and now remember I have to) ... aside from that something really I couldn't understand when I tried to solve my own issue, by testing the value first by using this method: print(rooms.popFirst().key!) half of my database values got nil value ?!! and if I don't include that method everything works fine anyways if you can't imagine that nonetheless I really wish your suggestion or advice for getting all data with their own key value...
This is my code so far:
Database.database().reference().child("rooms").observe(.value, with: { (snapshot) in
print()
var rooms = snapshot.value as! [String:AnyObject]
for(_,value) in rooms {
if (rooms.popFirst()?.key) != nil{
let title = value["title"] as? String
let description = value["description"] as? String
let roomPictureUrl = value["Room Picture"] as? String
let longitude = value["Longtitude"] as? String
let latitude = value["Latitude"] as? String
let dateFrom = value["Date From"] as? String
let dateTo = value["Date To"] as? String
let owner = value["Owner"] as? String
let myRooms = Room(roomID: "XXX",title: title!, description: description!, roomPicutreURL: roomPictureUrl!, longitude: longitude!, latitude: latitude!, dateFrom: dateFrom!, dateTo: dateTo!, owner: owner!)
//print(rooms.popFirst()?.key)
self.rooms.append(myRooms)
self.tableView.reloadData()
}
}
})
Try this:
Database.database().reference().child("rooms").observe(.value, with: { (snapshot) in
var rooms = snapshot.value as! [String:AnyObject]
let roomKeys = Array(rooms.keys)
for roomKey in roomKeys {
guard
let value = rooms[roomKey] as? [String:AnyObject]
else
{
continue
}
let title = value["title"] as? String
let description = value["description"] as? String
let roomPictureUrl = value["Room Picture"] as? String
let longitude = value["Longtitude"] as? String
let latitude = value["Latitude"] as? String
let dateFrom = value["Date From"] as? String
let dateTo = value["Date To"] as? String
let owner = value["Owner"] as? String
let myRooms = Room(roomID: "XXX",title: title!, description: description!, roomPicutreURL: roomPictureUrl!, longitude: longitude!, latitude: latitude!, dateFrom: dateFrom!, dateTo: dateTo!, owner: owner!)
print(roomKey)
self.rooms.append(myRooms)
self.tableView.reloadData()
}
}
})
To get the key from snapshot you can use following lines of code it will give you result like -> Kqwewsds12 -> your child Details
let dictValues = [String](snapshot.keys)
print(dictValues[0]) //Output -- Kqwewsds12
I am getting this error: "Type 'Any' has no subscript members" when trying to run this block of code:
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
itemRef = snapshot.ref
if let postContent = snapshot.value!["content"] as? String { // error
content = postContent
} else {
content = ""
}
}
I have been searching for an answer and couldn't find one that solved this problem with FireBase. How would I solve this error?
snapshot.value has the type Any?, so you need to cast it to the underlying type before you can subscript it. Since snapshot.value!.dynamicType is NSDictionary, use an optional cast as? NSDictionary to establish the type, and then you can access the value in the dictionary:
if let dict = snapshot.value as? NSDictionary, postContent = dict["content"] as? String {
content = postContent
} else {
content = ""
}
Or, you can do it as a one-liner:
content = (snapshot.value as? NSDictionary)?["content"] as? String ?? ""
I have also a codepiece which allows you to access to the values of the child nodes. I hope this helps you:
if let snapDict = snapShot.value as? [String:AnyObject] {
for child in snapDict{
let shotKey = snapShot.children.nextObject() as! FIRDataSnapshot
if let name = child.value as? [String:AnyObject]{
var _name = name["locationName"]
print(_name)
}
}
}
Best regards,
Nazar Medeiros
Having trouble which is probably so minor but my searches turn up nothing. I have a json model as follows :
//quick syntax to give you an idea of the model
{user:
{"name": "",
"password": "",
"medium" : {
{"title":"",
{"description":""}}}
I'm getting the above data model from a GET request to user and it returns all the info above but when i try to parse the "medium" information such as "title" & "description" I'm having no luck. I get these responses in Xcode that say
"Value of object 'AnyObject' not unwrapped, did you mean to use ! or ?"
and then when i click on the round red Xcode message to fix it it places !s and ?s everywhere but the error remains. Here is my parse method which worked perfectly fine when I was parsing only from the "medium". Any idea what I'm doing wrong?
a portion of the parse method where i get the same error for each attribute:
all lines with the same error indicated by *
// Parse JSON data
let jsonMedium = jsonResult?["user"] as! [AnyObject] //media where user is
for jsonMedia in jsonMedium {
let media = Media()
*media.title = jsonMedia["medium"]["title"] as! String
*media.description = jsonMedia["medium"]["description"] as! String
*media.category = jsonMedia["medium"]["category"] as! String
*media.image = jsonMedia["medium"]["image"] as! String
*if let IDer = jsonMedia["medium"]["id"] as? Int{
var stringIder = String(IDer)
media.identifierString = stringIder
}
Still no luck with anything. I don't understand why it works with regular JSON but Xcode won't accept anything when I try to obtain nested. All of your help has been appreciated. In the meantime here's the full method if it helps any further
func parseJsonData(data: NSData) -> [Media] {
var medium = [Media]()
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data,
options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
// Parse JSON data
let jsonMedium = jsonResult?["media"] as! [AnyObject]
for jsonMedia in jsonMedium {
let media = Media()
media.title = jsonMedia["medium"]["title"] as! String
media.description = jsonMedia["medium"]["description"] as! String
media.category = jsonMedia["medium"]["category"] as! String
media.image = jsonMedia["medium"]["image"] as! String
if let IDer = jsonMedia["medium"]["id"] as? Int{
var stringIder = String(IDer)
media.identifierString = stringIder
}
medium.append(media)
}
} catch {
print(error)
}
return medium
}
let json = [
"user" : [
"name" : "My Name",
"password" : "My Password",
"medium" : [
"title" : "My Title",
"description" : "My Description"
]
]
]
if let userJson = json["user"] as? [String : AnyObject] {
if let name = userJson["name"] as? String {
print("name: \(name)")
}
if let password = userJson["password"] as? String {
print("password: \(password)")
}
if let mediumJson = userJson["medium"] as? [String : AnyObject] {
if let title = mediumJson["title"] as? String {
print("title: \(title)")
}
if let description = mediumJson["description"] as? String {
print("description: \(description)")
}
}
}
Maybe it helps
let request : ASIFormDataRequest = ...your request
if request.responseString() != nil {
var jsonResponse : Dictionary<String, AnyObject>?
do{
jsonResponse = try NSJSONSerialization.JSONObjectWithData(request.responseData(), options: NSJSONReadingOptions.AllowFragments) as? Dictionary<String, AnyObject>
} catch _ {
//some error
}
}
FIXED IT! Took an entire day of deep thought and google/youtube/stack/brainstorming and your help but it was one changed line that got the whole thing going
// Parse JSON data
let jsonMedium = jsonResult?["user"]!["medium"] as? [AnyObject]
for jsonMedia in jsonMedium! {
let media = Media()
media.title = jsonMedia["title"] as! String
media.description = jsonMedia["description"] as! String
instead of :
let jsonMedium = jsonResult?["user"] as! [AnyObject] //media where user is
for jsonMedia in jsonMedium {
let media = Media()
*media.title = jsonMedia["medium"]["title"] as! String
*media.description = jsonMedia["medium"]["description"] as! String