I am getting a document from firebase in swift. However the line isn't being run and is not getting the data.
This is my code:
let db = Firestore.firestore()
db.collection("chats").document(userDefaults.string(forKey: "currentGroup")!).collection("messages").document("variable").getDocument { (document, error) in
if error != nil{
print("error getting document")
}
else{
let documentData = document!.data()
let startNumOfMessages = documentData!["numOfMessages"] as! Int
var messageArray: Array<String> = []
if startNumOfMessages > 0 {
for message in 1...startNumOfMessages{
print(message)
//THIS LINE ISNT RUNNING
db.collection("chats").document(self.userDefaults.string(forKey: "currentGroup")!).collection("messages").document("\(message)").getDocument { (messageDoc, err) in
if err != nil{
print("Error getting message \(message)")
}
else{
if messageDoc!.exists && messageDoc != nil{
let messData = messageDoc!.data()
print(messData!["message"]!)
messageArray.append(messData!["message"] as! String)
}
else{
print("error in document")
}
}
}
}
//Display them
for num in 0...messageArray.count{
let label = UILabel()
label.text = messageArray[num]
self.stackView.addArrangedSubview(label)
}
}
}
}
The line below the comment is the line that isn't running. And the line that says label.text = messageArray[num] displays an error
Fatal error: Index out of range
Showing it doesn't get the data.
You miss the asynchronous way use DispatchGroup ( numbered from 1 to 4 )
let db = Firestore.firestore()
db.collection("chats").document(userDefaults.string(forKey: "currentGroup")!).collection("messages").document("variable").getDocument { (document, error) in
if error != nil{
print("error getting document")
}
else{
let documentData = document!.data()
let startNumOfMessages = documentData!["numOfMessages"] as! Int
var messageArray: Array<String> = []
if startNumOfMessages > 0 {
let g = DispatchGroup() /// 1
for message in 1...startNumOfMessages{
print(message)
//THIS LINE ISNT RUNNING
g.enter() /// 2
db.collection("chats").document(self.userDefaults.string(forKey: "currentGroup")!).collection("messages").document("\(message)").getDocument { (messageDoc, err) in
if err != nil{
print("Error getting message \(message)")
}
else{
if messageDoc!.exists && messageDoc != nil{
let messData = messageDoc!.data()
print(messData!["message"]!)
messageArray.append(messData!["message"] as! String)
}
else{
print("error in document")
}
}
g.leave() /// 3
}
}
g.notify(queue: .main) { /// 4
//Display them
for num in 0...messageArray.count{
let label = UILabel()
label.text = messageArray[num]
self.stackView.addArrangedSubview(label)
}
}
}
}
}
Related
I want to multiply the two firebase values and get the result to display in the Label, without success
Can anyone give me some advice
func UserInfo(){
let firestoreDB = Firestore.firestore()
firestoreDB.collection("Usermoney").whereField("email", isEqualTo: Auth.auth().currentUser!.email!).addSnapshotListener { snapshot, error in
if error != nil {
print(error?.localizedDescription ?? "Error while getting data from server!" )
}else{
if snapshot?.isEmpty != true && snapshot != nil {
for document in snapshot!.documents{
if let money = document.get("money") as? String{
if let q8 = document.get("q8") as? String{
self.money.text = money
self.q8.text = "+"+q8+"%"
let tip = money * q8
self.win.text = String(format: "$%.2f", tip)
}
}
}
}
}
}
}
Try This
func UserInfo(){
let firestoreDB = Firestore.firestore()
firestoreDB.collection("Usermoney").whereField("email", isEqualTo: Auth.auth().currentUser!.email!).addSnapshotListener { snapshot, error in
if error != nil {
print(error?.localizedDescription ?? "Error while getting data from server!" )
}else{
if snapshot?.isEmpty != true && snapshot != nil {
for document in snapshot!.documents{
if let money = document.get("money") as? String{
if let q8 = document.get("q8") as? String{
self.money.text = money
self.q8.text = "+"+q8+"%"
if let moneyDouble = Double(money), let q8Double = Double(q8){
let tip = moneyDouble * q8Double
self.win.text = String(format: "$%.2f", tip)
}
}
}
}
}
}
}
}
Please look at my TableView with custom Cell here. I fetched the data from Firestore (and sort it by date descendingly) real time and insert it into the meal array locally. When I clicked the 'eat' button and add a new meal, the 'eat' button isn't sorted correctly?
Here is my code for loadMenu() function and eatButtonPressed() function
loadMenu()
func loadMenu() {
let menuRef = db.collection("menu").document()
db.collection("menu").order(by: "date", descending: true).whereField("family_id", isEqualTo: "\(UserDefaults.standard.string(forKey: "family_id")!)")
.addSnapshotListener { querySnapshot, error in
self.menu = []
guard let documents = querySnapshot?.documents else {
print("Error fetching documents: \(error!)")
return
}
let name = documents.map { $0["name"] ?? [""] }
let family_id = documents.map { $0["family_id"] ?? [0] }
let portions = documents.map { $0["portions"] ?? [""] }
let menu_id = documents.map { $0["menu_id"] ?? [""]}
let isOpened = documents.map { $0["isOpened"] ?? [""]}
if name != nil || name[0] as! String != "" {
for i in 0..<name.count {
self.menu.append(Menu(menu_id: menu_id[i] as! String, name: name[i] as! String, family_id: family_id[i] as! String, portions: portions[i] as! Int, isOpened: isOpened[i] as! Bool))
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
eatButtonPressed()
func eatButtonPressed(cell: TopPartTableViewCell, send: UIButton) {
var likeRef = self.db.collection("like").document("\(Auth.auth().currentUser!.uid)_\(self.menu[send.tag].menu_id)")
self.db.collection("dislike").document("\(Auth.auth().currentUser!.uid)_\(self.menu[send.tag].menu_id)").delete() { err in
if let err = err {
print("Error removing document: \(err)")
} else {
print("Document successfully removed!")
}
}
likeRef.getDocument { (document, error) in
if let document = document, document.exists {
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
self.db.collection("like").document("\(Auth.auth().currentUser!.uid)_\(self.menu[send.tag].menu_id)").delete() { err in
if let err = err {
print("Error removing document: \(err)")
} else {
print("Document successfully removed!")
}
}
} else {
likeRef.setData([
"like_id": "\(likeRef.documentID)",
"user_id": "\(Auth.auth().currentUser!.uid)",
"menu_id": "\(self.menu[send.tag].menu_id)"
]) { err in
if let err = err {
print("Error writing document: \(err)")
} else {
print("Document successfully written!")
}
}
}
}
let user_liked = like.contains(where: {$0.menu_id == menu[send.tag].menu_id}) && like.contains(where: {$0.user_id == Auth.auth().currentUser!.uid})
if !user_liked {
send.backgroundColor = UIColor(named: "BrandOrange")
send.tintColor = UIColor.white
cell.dontEatButton.backgroundColor = UIColor.white
cell.dontEatButton.tintColor = UIColor.black
} else {
send.backgroundColor = UIColor.white
send.tintColor = UIColor.black
}
}
Anyone can help me solve this problem?
Thank you.
The above method doesn't seem to be relevant to the question.
You have added a new item and a cell has been added for that item.
If you look at the detailed structure of the cell, I think you can figure out the cause.
If the cell default button state is Eat, it is most likely not initialized properly.
This is my code
let db = Firestore.firestore()
db.collection("chats").document(userDefaults.string(forKey: "currentGroup")!).collection("messages").document("variable").addSnapshotListener { (snapshot, error) in
if error != nil{
print("Error fetching document")
}
else{
let documentData = snapshot!.data()
print(documentData!["numOfMessages"])
self.numOfMessages = documentData!["numOfMessages"] as! Int
print(self.numOfMessages)
//Get texts and display them
db.collection("chats").document(self.userDefaults.string(forKey: "currentGroup")!).collection("messages").document("\(self.numOfMessages)").getDocument { (document, err) in
let newMessageData = document!.data()
let newMessage = newMessageData!["message"] as! String
let newAuthor = newMessageData!["author"] as! String
let authorLabel = UILabel()
authorLabel.text = newAuthor
self.stackView.addArrangedSubview(authorLabel)
let label = UILabel()
label.text = newMessage
self.stackView.addArrangedSubview(label)
}
}
}
This line self.numOfMessages = documentData!["numOfMessages"] as! Int has an error of
Could not cast value of type 'NSTaggedPointerString' (0x1ed6ed450) to 'NSNumber' (0x1ed6f98c8).
This is every since I deleted the collection messages and replaced it with one of the exact same name
The value that documentData!["numOfMessages"] returns is Optional(1) even though in firebase the value is 2.
This is how the Firestore looks:
Either you are listening to the wrong document (perhaps because of an incorrect user default) or you are unwrapping the value incorrectly. To debug this, try the following and see what the problem actually is. The following is a more idiomatic way of handling documents.
if let currentGroup = userDefaults.string(forKey: "currentGroup") {
print(currentGroup) // this could be your problem
Firestore.firestore().collection("chats").document(currentGroup).collection("messages").document("variable").addSnapshotListener { (snapshot, error) in
if let snapshot = snapshot {
if let numOfMessages = snapshot.get("numOfMessages") as? Int {
print(numOfMessages)
} else {
print("field error")
}
} else if let error = error {
print(error)
}
}
} else {
print("no current group")
}
I am trying to upload two files to firebase storage at the same time. From what I understand this is not possible so what I did was try to upload one first and then the next file once the first is done.
It is working now, however the upload speed is very slow. Is this because of an issue with my code or is it because Im waiting for two uploads as opposed to one.
var index = 0
var urls = [String]()
fileprivate func uploadToServer(data: Any) {
if index == 0 {
let filename = NSUUID().uuidString
let storageRef = Storage.storage().reference().child("posts").child(filename)
storageRef.putData(data as! Data, metadata: nil) { (metadata, err) in
if let err = err {
self.navigationItem.rightBarButtonItem?.isEnabled = true
print("Failed to upload post image:", err)
self.showHUDwithError(error: err)
return
}
storageRef.downloadURL(completion: { (downloadURL, err) in
if let err = err {
print("Failed to fetch downloadURL:", err)
self.showHUDwithError(error: err)
return
}
guard let thisUrl = downloadURL?.absoluteString else { return }
self.urls.append(thisUrl)
self.index = self.index + 1
if self.type == "image" {
// we are done then so do the save to server call here
self.saveToDatabaseWithImageUrl()
} else {
self.uploadToServer(data: self.videoUrl as Any)
}
})
}
return
}
if index == 1 {
let filename = NSUUID().uuidString
let storageRef = Storage.storage().reference().child("posts").child(filename)
storageRef.putFile(from: data as! URL, metadata: nil) { (metadata, err) in
if let err = err {
self.navigationItem.rightBarButtonItem?.isEnabled = true
print("Failed to upload post image:", err)
self.showHUDwithError(error: err)
return
}
storageRef.downloadURL(completion: { (downloadURL, err) in
if let err = err {
print("Failed to fetch downloadURL:", err)
self.showHUDwithError(error: err)
return
}
guard let thisUrl = downloadURL?.absoluteString else { return }
self.urls.append(thisUrl)
self.saveToDatabaseWithImageUrl()
self.index = 0
})
}
}
}
What's an issue in my Query?
let uid = Auth.auth().currentUser?.uid
let itemId = selectedItem.objectID
var isOn = false
func like(){
if isOn == true {
likeRef.delete(){err in
if let err = err{
print("Error")
}else{
self.likeImageView.image = UIImage(named: "detail_like.png")
self.isOn = false
print("delete Success")
}
}
}else if isOn == false {
let like = Like(uid: uid!, itemId: itemId!, status: true)
db.collection("likes").addDocument(data: like.dictionary()){ err in
if let err = err {
print("Error adding document: \(err)")
} else {
self.isOn = true
self.likeImageView.image = UIImage(named: "like_after.png")
}
}
print(isOn)
}
}
It has a value to addDocument.
value is not nil.
I encountered this error for the first time.
what is the reason?
There was an error because there was not a value for let itemId = selectedItem.objectID.
Therefore, when I set it directly in if without declaring a constant, the error disappeared.
if isOn == true {
db.collection("likes").document(likeObjectID).delete(){err in
if let err = err{
print("Error")
}else{
self.likeImageView.image = UIImage(named: "detail_like.png")
self.isOn = false
print("delete Success")
}
}
}else if isOn == false {
let like = Like(uid: uid!, itemId: itemId!, status: true)
db.collection("likes").addDocument(data: like.dictionary()){ err in
if let err = err {
print("Error adding document: \(err)")
} else {
self.isOn = true
self.likeImageView.image = UIImage(named: "like_after.png")
}
}
print(isOn)
}