I have a number field from Cloud Firestore that needs to be displayed as a string within a label.
Usually, if the field were a string, I can just execute this code
db.collection("users").document(uid ?? "UID not yet loaded in viewDidLoad()")
.addSnapshotListener { snapshot, error in
if error != nil {
print(error ?? "Couldn't update text field TextUser according to database")
} else {
if let dbUsername = snapshot?["username"] as? String {
self.textUser?.text = dbUsername
}
That works because "username" in the document is of a value string.
But this won't work because "cash" in the document is of a value number.
if let dbCash = snapshot? ["cash"] as? String {
self.labeCash?.text = dbCash
}
I might just have to convert the number, whatever type they use, into a string. But how would I do that? Thanks!
Can you try
if let dbCash = snapshot? ["cash"] as? NSNumber {
self.labeCash?.text = dbCash.stringValue
}
Related
This question already has an answer here:
How to subscript a dictionary that is stored inside a dictionary in swift?
(1 answer)
Closed 4 months ago.
I have the following code.
func setUserToken(_ user: NSDictionary) {
self.userId = user["user"]["id"] as! String;
I get the error "Value of type Any has no subscripts". What am I doing wrong?
You need to specify your json before parsing it. Try This:
func setUserToken(_ user: NSDictionary) {
guard let userData = user as? NSDictionary else{return}
guard let user = userData["user"] as? String else{return}
self.userid = user["id"] as? String else{return}
}
The type of any lookup from a NSDictionary is Any. You know (or think you know) it is another dictionary, but Swift does not. You must establish the type before you can do the second lookup.
func setUserToken(_ user: NSDictionary) {
if let userDict = user["user"] as? NSDictionary {
// We now know “user” is a valid key and its value
// is another NSDictionary
if let userId = userDict["id"] as? String {
// We now know “id” is a valid key and its
// value is of type String which has been
// assigned to userId. Now assign it to the
// property
self.userId = userId
return
}
}
// If we get here, something went wrong.
// Assign a reasonable default value.
self.userId = “user unknown”
}
You can do it in a single line using optional chaining and the nil coalescing operator:
self.userId = ((user["user"] as? NSDictionary)?["id"] as? String) ?? “user unknown”
I am trying to iterate over the following dictionary:
Dictionary in Firebase
This is my code:
Global.sharedInstance.db.collection("usuarios").getDocuments { (snapshot, error) in
if error != nil {
print("error de lectura usuarios...")
} else {
if let snapshot = snapshot {
for document in snapshot.documents {
let data = document.data()
let txtIdentificador = data["identificador"] as? String ?? ""
let txtBio = data["bio"] as? String ?? ""
let txtNombre = data["nombre_usuario"] as? String ?? ""
let txtFotoPerfil = data["foto_perfil"] as? String ?? ""
var arrFotos = data["fotos"] as? [String: [String:String]]
}
}
}
}
I am able to retrieve the first few lines, like the id, the biography, name, etc.
But when I try to access the array of dictionary I have no idea.
This is the main idea:
I have a set of users, which I iterate over with the first loop 'for document in documents...", then each user has a set of photos. I want to iterate over the 3 photos, and in each iteration I want to retrieve the fields, so I can create a object called Image and associate the user with the 'hasUpload(Image)'.
I would like to know how to iterate over X photos an in each iteration retrieve the fields.
Something like this:
var arrFotos = data["fotos"] as? [String: [String:String]]
for foto in arrFotos {
for (key,value) in foto {
}
}
I get the error: For-in loop requires '[String : [String : String]]?' to conform to 'Sequence'; did you mean to unwrap optional?
A similar StackOverflow case can be found here and this is how they resolved it:
You can either do this, where x is the index and token is the element:
for (x, token) in transcriptCandidate.enumerated() {
}
Or this if you don't need the index:
for token in transcriptCandidate {
}
I'm trying to query an Array of user IDs, which are held in an Array in my Firestore database. This is working, and it is successfully displaying the UIDs in my console. I want to, then, find when field "uid" is equal to a member of the array. This is where it stops working. I cannot seem to be able to actually match the "uid" with a member of the followedUID Array.
I detail my code below. Any help would be greatly appreciated:
func getFollowingPosts() {
db.collection("iAmFollowing").document(currentUserID!).getDocument { (document, error) in
if error != nil {
print("ERROR")
} else {
if let document = document {
let followedUID = document["uid"] as? Array ?? [""]
print("followed UID is \(followedUID)")
let searchedInfo = self.db.collection("posts").whereField("uid", isEqualTo: followedUID)
let refinedInfo = searchedInfo.order(by: "Alpha", descending: true)
refinedInfo.getDocuments { (documents, error) in
guard let documents = documents else {
print("NO DOCUMENTS")
return
}
for documents in documents.documents {
let title = documents.get("Title") as! String
let content = documents.get("Content") as! String
let username = documents.get("username") as! String
let postID = documents.get("postID")
let counter = documents.get("counter")
self.titleArray.append(title)
self.contentArray.append(content)
self.usernameArray.append(username)
self.postIDArray.append(postID as! Int)
self.effectsLabelArray.append(counter as! Int)
print(self.titleArray)
self.tableView.reloadData()
}
}
}
}
}
}
Thanks!
Your query is asking for documents where the uid field is exactly equal to the given value:
db.collection("posts").whereField("uid", isEqualTo: followedUID)
If the uid field is an array, this query will never find anything, because an array is never equal to a string.
If you want to see if a field value is one of many values, use an "in" query:
db.collection("posts").whereField("uid", in: followedUID)
I am working on an app which fetches data from Firebase. The code I am going to show you works just fine but even as a rookie I know that the implementation should be waaaaay better. I just can't really figure out how to refactor this.
Here's the TLDR:
I have created a Data Model which I used for pasing BlogPosts. I use a Struct for this and in the initial version all of my properties were of type String.
However, apart from Strings for Title and Summary, my Posts also contain an URL to an image and also a Date (post date).
I want to be able to return from my BlogPost object more concrete objcets such as an already created URL or a Date object.
Like I said, I know my implementation is bad, and I want to learn a better way of typecasting in such a way that I can achieve the behaviour described above.
Here is the implementation of my BlogPost data model:
import Foundation
import FirebaseDatabase
struct BlogPost {
let key: String
let title: String
let body: String
let summary: String
let author: String?
let liveSince: Date
let featuredImageLink: URL?
let itemReference:DatabaseReference?
init(snapshot: DataSnapshot) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-mm-dd"
key = snapshot.key
itemReference = snapshot.ref
if let snapshotDictionary = snapshot.value as? NSDictionary, let postTitle = snapshotDictionary["Title"] as? String {
title = postTitle
} else {
title = "Cannot display Title for this item :("
}
if let snapshotDictionary = snapshot.value as? NSDictionary, let postBody = snapshotDictionary["Body"] as? String {
body = postBody
} else {
body = "Cannot display Body for this item :("
}
if let snapshotDictionary = snapshot.value as? NSDictionary, let postSummary = snapshotDictionary["Summary"] as? String {
summary = postSummary
} else {
summary = "Due to some weird error, the Summary for this item cannot be displayed. Insert more coffee and Pizza in developer"
}
if let snapshotDictionary = snapshot.value as? NSDictionary, let postAuthor = snapshotDictionary["Author"] as? String {
author = postAuthor
} else {
author = "Nobody wrote this :("
}
if let snapshotDictionary = snapshot.value as? NSDictionary, let postImageLink = snapshotDictionary["FeaturedImage"] as? String {
featuredImageLink = URL(string: postImageLink)!
} else {
featuredImageLink = URL(string:"https://someimagelink")!
}
if let snapshotDictionary = snapshot.value as? NSDictionary, let liveDate = snapshotDictionary["LiveSince"] as? String {
if let live = dateFormatter.date(from: liveDate) {
liveSince = live
} else {
liveSince = dateFormatter.date(from: "1990-06-26")!
}
} else {
liveSince = dateFormatter.date(from: "1990-06-26")!
}
}
}
Any constructive feedback is more than welcome as I do really want to understand how to do this properly or if it even makes sense to do so in the first place!
Thank you very much for your replies in advance!
I have some suggestions. It looks you keep using conditional binding to unwrap the snapshsot.value while casting it as an NSDictionary. Since unwrapping this value is prerequisite to unwrapping the other values, why not just use a guard statement to unwrap it? In your guard statement, you can then default initialize all the properties in your struct. Alternatively, if you are not adamant about default initializing your properties, you can just use a failable initializer and just return nil in the guard statement.
guard let snapshotDictionary = snapshot.value as? NSDictionary else {
title = "Cannot display Title for this item :("
body = "Cannot display Body for this item :("
summary = "Due to some weird error, the Summary for this item cannot be
displayed. Insert more coffee and Pizza in developer"
...
...
}
Here is my JSON data which I am getting from server.
{
"result": "SUCCESS",
"resultcode": "000",
"balance": "-32020",
"available": "-32020",
"reserved": 0
}
When I am trying to parse these JSON data, App crashed and throws Could not cast value of type '__NSCFNumber' (0x1a17dab60) to 'NSString' (0x1a17e5798).
I know the issue is about data type. But when I get Positive value for reserved key in above JSON data, it shows string value in JSON data, but when i get Negative value of reserved key, it return Numeric data type.
Here is the code Which i am reading data.
self.response?.objectForKey("reserved") as! NSString
So How to deal with this kind of issue?
You can parse data using if let statements. Check below
if let reservedNum = JSON["reserved"] as? Double {
print(reservedNum)
} else if let reservedString = JSON["reserved"] as? String {
print(reservedString)
} else {
print("Error Parsing Data")
}
if let safeResult = JSON["result"] as? String {
print(safeResult)
}
And same for the rest and handle the response in a Modal.
What about something like this:
var reserved:Double?
if let reserved_string=response.value(forKey: "reserved") as? NSString{
reserved=reserved_string.integerValue
}
if let reserved_float=response.value(forKey: "reserved") as? Double{
reserved=reserved_float
}
Its because in your json response , reserved key is NSCFNumber type so you can't directly force wrap this into NSString so use this way :
if let mReserved = self.response?.objectForKey("reserved") as? Int {
print(mReserved)
}
You have to check what kind of data type is with Optional.
if self.response?.objectForKey("reserved") as? NSString{
//Do something with NSString
}else if self.response?.objectForKey("reserved") as? NSNumber{
//Do something with NSNumber
}else {
print("Error")
}
Try this below code
let reservedStr = String(response.value(forKey: "reserved") as! Double)