Database fetch exists only in its own function - ios
I am trying to fetch all the user names in my database but the nameArray only contains values while its inside that function, how can I fix this?
DataService.instance.getAllUserNamesPlease { (returnedNamesArray) in
self.nameArray = returnedNamesArray
}
for userName in nameArray {
if(userName.lowercased() == name!.lowercased()){
self.userNameTaken = true
self.progressView.progress = Float(progress / self.nameArray.count)
progress += 1/self.nameArray.count
break
}
}
nameArray is empty in this loop
func getAllUserNamesPlease(handler: #escaping (_ userNames: [String]) -> ()){
REF_USERS.observeSingleEvent(of: .value) { (userNameSnapshot) in
guard let userNameSnapshot = userNameSnapshot.children.allObjects as? [DataSnapshot] else {return}
var namesArray = [String]()
for names in userNameSnapshot {
let name = names.childSnapshot(forPath: "userName").value as? String ?? "No Name"
namesArray.append(name)
}
handler(namesArray)
}
}
Any code that needs access to the results of an asynchronous call, should be inside that callback/completion handler. So your loop over nameArray, needs to be inside the {} braces:
DataService.instance.getAllUserNamesPlease { (returnedNamesArray) in
self.nameArray = returnedNamesArray
for userName in nameArray {
if(userName.lowercased() == name!.lowercased()){
self.userNameTaken = true
self.progressView.progress = Float(progress / self.nameArray.count)
progress += 1/self.nameArray.count
break
}
}
}
}
Related
Firestore query multiple documents with for loop
I am trying to query multiple documents using a for-loop. My database set up looks like this: users -> wishlists -> all the users Wishlists(containing different Wishlists with name) -> wünsche The items are getting retrieved but in the wrong order. I tried couple of different things but nothing worked so far. func getWishes() { let db = Firestore.firestore() let userID = Auth.auth().currentUser!.uid var counter = 0 for list in self.dataSourceArray { print(list.name) // -> right order } for list in self.dataSourceArray { db.collection("users").document(userID).collection("wishlists").document(list.name).collection("wünsche").getDocuments() { ( querySnapshot, error) in print(list.name) // -> wrong order if let error = error { print(error.localizedDescription) }else{ // create new Wish array var wList: [Wish] = [Wish]() for document in querySnapshot!.documents { let documentData = document.data() let wishName = documentData["name"] wList.append(Wish(withWishName: wishName as! String, checked: false)) } self.dataSourceArray[counter].wishData = wList counter += 1 } } } } I am calling this function inside another function that retrieves all the wishlist in the right order: func getWishlists() { let db = Firestore.firestore() let userID = Auth.auth().currentUser!.uid db.collection("users").document(userID).collection("wishlists").order(by: "listIDX").getDocuments() { ( querySnapshot, error) in if let error = error { print(error.localizedDescription) }else { // get all documents from "wishlists"-collection and save attributes for document in querySnapshot!.documents { let documentData = document.data() let listName = documentData["name"] let listImageIDX = documentData["imageIDX"] // if-case for Main Wishlist if listImageIDX as? Int == nil { self.dataSourceArray.append(Wishlist(name: listName as! String, image: UIImage(named: "iconRoundedImage")!, wishData: [Wish]())) // set the drop down menu's options self.dropDownButton.dropView.dropDownOptions.append(listName as! String) self.dropDownButton.dropView.dropDownListImages.append(UIImage(named: "iconRoundedImage")!) }else { self.dataSourceArray.append(Wishlist(name: listName as! String, image: self.images[listImageIDX as! Int], wishData: [Wish]())) self.dropDownButton.dropView.dropDownOptions.append(listName as! String) self.dropDownButton.dropView.dropDownListImages.append(self.images[listImageIDX as! Int]) } // reload collectionView and tableView self.theCollectionView.reloadData() self.dropDownButton.dropView.tableView.reloadData() } } self.theCollectionView.isHidden = false self.getWishes() } } *DataSourceArray in the right order: * Main Wishlist, Goals, boost Output from 2nd print-test: boost, Goals, Main Wishlist
Seems as though you are trying to make a bunch of API calls at once and it is returning values at different times. You could attempt to make your calls synchronously to maintain order or you could try to use dispatch groups like the pseudo code below: let myGroup = DispatchGroup() struct DataItem { let order: Int let data: DataYouWantToSave } var fetchedData = [DataItem]() for i in list { myGroup.enter() let dataItem = DataItem() dataItem.order = i db.collection... print("Finished request \(i)") dataItem.data = DataYouWantToSave fetchedData.apped(dataItem) myGroup.leave() } } myGroup.notify(queue: .main) { print("Finished all requests.") // Reorder your array of data items here. let sortedArray = fetchedData.sorted(by: { $0.order > $1.order }) // If you just want the array of data values let newData: [DataYouWantToSave] = sortedArray.map { $0.data } }
How to fetch contacts and store in array on iOS?
I am working on a Tinder Swiping application for iOS Contacts. I have imported the contacts library and successfully have gotten the contacts to print in the console. However, I am trying to dynamically add those names to a card like Tinder. I have created a model class to hold the name, however, I am unable to append my data to that model. struct ContactInfo { var name: String } let contactInfo = [ContactInfo]() func fetchContacts(){ let contactStore = CNContactStore() var contacts = [CNContact]() let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)] let request = CNContactFetchRequest(keysToFetch: keys) do { try contactStore.enumerateContacts(with: request) { (contact, stop) in contacts.append(contact) var info = contact.givenName + " " + contact.familyName print(info) } } catch { print(error.localizedDescription) } } var userModels : [ContactInfo] = { var model : [ContactInfo] = [] for n in 1...10 { model.append(ContactInfo(name: names[Int(arc4random_uniform(UInt32(names.count)))])) } return model }() I would like all of my contacts to append to the model variable which is then returned to the cards.
As my understanding, the enumerateContacts is asynchronous. It means that, when your app is executing the line to create the userModels array, the contacts aren't fetched yet : so your array stays empty. I would try to move the userModels array creation in another controller, where you are displaying your cards. To achieve that, you can use a delegate, that receives the fetched contacts as a parameter. Then, you can assign your array with this parameter content and create your cards' content. Here is a great tutorial on how to use a delegate with Swift. Hope this will help you.
I have created helper class for that. That might help you. Example ContactSyncHelper.sharedInstance.getAllContacts { (contacts, error) in if error { print("error") }else { print(contacts) } } ContactSyncHelper import UIKit import Foundation import Contacts let kphone_number = "phone_number" let kcountry_code = "country_code" class ContactSyncHelper: NSObject { static let sharedInstance: ContactSyncHelper = { let instance = ContactSyncHelper() // setup code return instance }() // MARK: - Initialization Method override init() { super.init() } //Example // ContactSyncHelper.sharedInstance.getAllContacts { (contacts, error) in // if error { // print("error") // }else { // print(contacts) // } // } func getAllContacts(completion: ([NSMutableDictionary],Bool) -> ()) { switch CNContactStore.authorizationStatus(for: .contacts) { // Update our UI if the user has granted access to their Contacts case .authorized: break // Prompt the user for access to Contacts if there is no definitive answer case .notDetermined : completion([],true) break // Display a message if the user has denied or restricted access to Contacts case .denied, .restricted: //CommData.showAlert(self, withMsg: "Permission was not granted for Contacts.", withTitle: "Privacy Warning!", action: nil) completion([],true) break } let contactStore = CNContactStore() let keysToFetch = [ CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactImageDataAvailableKey, CNContactThumbnailImageDataKey] as [Any] // Get all the containers var allContainers: [CNContainer] = [] do { allContainers = try contactStore.containers(matching: nil) } catch { print("Error fetching containers") } var arrayNumbers: [NSMutableDictionary] = [] for container in allContainers { let fetchPredicate = CNContact.predicateForContactsInContainer(withIdentifier: container.identifier) do { let containerResults = try contactStore.unifiedContacts(matching: fetchPredicate, keysToFetch: keysToFetch as! [CNKeyDescriptor]) containerResults.forEach { (contact:CNContact) in contact.phoneNumbers.forEach { (justPhone:CNLabeledValue) in let numberValue = justPhone.value let countryCode = numberValue.value(forKey: "countryCode") as? String var strphone = numberValue.stringValue strphone = strphone.replacingOccurrences(of: "(", with: "") strphone = strphone.replacingOccurrences(of: ")", with: "") strphone = strphone.replacingOccurrences(of: "-", with: "") strphone = strphone.replacingOccurrences(of: "+", with: "") strphone = strphone.components(separatedBy: .whitespaces).joined() if strphone.hasPrefix("0"){ strphone.remove(at: (strphone.startIndex)) } if(countryCode != nil) { var countryCode1:String = self.getCountryPhonceCode(country: countryCode!) if strphone.hasPrefix(countryCode1) { strphone = strphone.deletingPrefix(countryCode1) } countryCode1 = "+\(countryCode1)" let dict = NSMutableDictionary() dict.setValue(strphone, forKey: kphone_number) dict.setValue(countryCode1, forKey: kcountry_code) arrayNumbers.append(dict) } } } } catch { print("Error fetching results for container") } } completion(arrayNumbers,false) } func getCountryPhonceCode (country : String) -> String { if country.count == 2 { let x : [String] = ["972","IL","93","AF","355","AL","213","DZ","1","AS","376","AD","244","AO","1","AI","1","AG","54","AR","374","AM","297","AW","61","AU","43","AT","994","AZ","1","BS","973","BH","880","BD","1","BB","375","BY","32","BE","501","BZ","229","BJ","1","BM","975","BT","387","BA","267","BW","55","BR","246","IO","359","BG","226","BF","257","BI","855","KH","237","CM","1","CA","238","CV","345","KY","236","CF","235","TD","56","CL","86","CN","61","CX","57","CO","269","KM","242","CG","682","CK","506","CR","385","HR","53","CU" ,"537","CY","420","CZ","45","DK" ,"253","DJ","1","DM","1","DO","593","EC","20","EG" ,"503","SV","240","GQ","291","ER","372","EE","251","ET","298","FO","679","FJ","358","FI","33","FR","594","GF","689","PF","241","GA","220","GM","995","GE","49","DE","233","GH","350","GI","30","GR","299","GL","1","GD","590","GP","1","GU","502","GT","224","GN","245","GW","595","GY","509","HT","504","HN","36","HU","354","IS","91","IN","62","ID","964","IQ","353","IE","972","IL","39","IT","1","JM","81","JP","962","JO","77","KZ","254","KE","686","KI","965","KW","996","KG","371","LV","961","LB","266","LS","231","LR","423","LI","370","LT","352","LU","261","MG","265","MW","60","MY","960","MV","223","ML","356","MT","692","MH","596","MQ","222","MR","230","MU","262","YT","52","MX","377","MC","976","MN","382","ME","1","MS","212","MA","95","MM","264","NA","674","NR","977","NP","31","NL","599","AN","687","NC","64","NZ","505","NI","227","NE","234","NG","683","NU","672","NF","1","MP","47","NO","968","OM","92","PK","680","PW","507","PA","675","PG","595","PY","51","PE","63","PH","48","PL","351","PT","1","PR","974","QA","40","RO","250","RW","685","WS","378","SM","966","SA","221","SN","381","RS","248","SC","232","SL","65","SG","421","SK","386","SI","677","SB","27","ZA","500","GS","34","ES","94","LK","249","SD","597","SR","268","SZ","46","SE","41","CH","992","TJ","66","TH","228","TG","690","TK","676","TO","1","TT","216","TN","90","TR","993","TM","1","TC","688","TV","256","UG","380","UA","971","AE","44","GB","1","US","598","UY","998","UZ","678","VU","681","WF","967","YE","260","ZM","263","ZW","591","BO","673","BN","61","CC","243","CD","225","CI","500","FK","44","GG","379","VA","852","HK","98","IR","44","IM","44","JE","850","KP","82","KR","856","LA","218","LY","853","MO","389","MK","691","FM","373","MD","258","MZ","970","PS","872","PN","262","RE","7","RU","590","BL","290","SH","1","KN","1","LC","590","MF","508","PM","1","VC","239","ST","252","SO","47","SJ","963","SY","886","TW","255","TZ","670","TL","58","VE","84","VN","284","VG","340","VI","678","VU","681","WF","685","WS","967","YE","262","YT","27","ZA","260","ZM","263","ZW"] var keys = [String]() var values = [String]() let whitespace = NSCharacterSet.decimalDigits //let range = phrase.rangeOfCharacterFromSet(whitespace) for i in x { // range will be nil if no whitespace is found // if (i.rangeOfCharacterFromSet(whitespace) != nil) { if (i.rangeOfCharacter(from: whitespace, options: String.CompareOptions.caseInsensitive) != nil) { values.append(i) } else { keys.append(i) } } let countryCodeListDict:NSDictionary = NSDictionary(objects: values as [String], forKeys: keys as [String] as [NSCopying]) if let _: AnyObject = countryCodeListDict.value(forKey: country.uppercased()) as AnyObject { return countryCodeListDict[country.uppercased()] as! String } else { return "" } } else { return "" } } }
How to know if a Firebase has fetched a value
I have three functions getNewOrder(),storeOrderDetails(_ details:[String:String]) and getUserInfo(_ userID:String). Function getNewOrder() is called first. It fetches new orders ( .childAdded values) and sends the dictionary to storeOrderDetails(_ details:[String:String]). storeOrderDetails(_ details:[String:String])then segregate all the values and callsgetUserInfo(_ userID:String)` by passing it userID which was present in its details. getUserInfo(_ userID:String) then fetches users details and returns user's information. However, the problem is [ userInfo = getUserInfo(_ userID:String) in storeOrderDetails(_ details:[String:String]) ] userInfo is always empty. Apparently func getUserInfo(_ userID:String) goes into a completion block after it has returned empty value. I want these three functions to execute in sequential way. Any advice is highly appreciated. Please follow the below Links to review my code. https://imgur.com/hNjvyDk https://imgur.com/J0LMXMg func childAdded(){ let ref = Database.database().reference().child("Orders").child(todaysDate) ref.observe(.childAdded) { (snapshot) in var details = [String:String]() if let orderID = snapshot.key as? String { ref.child(orderID).observeSingleEvent(of: .value, with: { (snap) in self.newOrderTextView.text = "" self.customerNameLabel.text = "" self.customerPhoneLabel.text = "" self.orderNumberLabel.text = "" let enumerator = snap.children while let rest = enumerator.nextObject() as? DataSnapshot { details[rest.key as? String ?? ""] = rest.value as? String ?? "" } self.storeUserDetails(details) }) } } } func storeUserDetails(_ details:[String:String]){ if details["CustomerID"] != nil { userInfo = getUserDetails(details["CustomerID"]!) print(userInfo) } if !userInfo.isEmpty{ let order = OrderDatabase() order.customerEmail = userInfo["Email"]! order.customerName = userInfo["Name"]! order.orderAcceptStatus = details["OrderStatus"]! order.customerOrderNumber = details["orderNumber"]! order.orderID = details["orderID"]! order.time = details["Time"]! order.customerFirebaseID = details["CustomerID"]! self.orderDatabase[details["orderNumber"]!] = order self.orderTable.reloadData() } } func getUserDetails(_ userID:String) -> [String:String]{ var details = [String:String]() let userDetailsReference = Database.database().reference().child("Users") userDetailsReference.child(userID).observeSingleEvent(of: DataEventType.value, with: { (snapshot) in if let dictionary = snapshot.value as? NSDictionary { self.customerNameLabel.text = dictionary.value(forKey: "Name") as? String self.customerPhoneLabel.text = dictionary.value(forKey: "Email") as? String details["Name"] = dictionary.value(forKey: "Name") as? String details["Email"] = dictionary.value(forKey: "Email") as? String } }) return details }
From what I can see here, I am betting that the issue you are facing has to do with the fact that the methods are asynchronous. So one thing is not completely finished and some other method gets fired too soon. There are a few ways to deal with this issue. One is completion handlers, and the other is adding observers. Below is an example of doing both for Firebase. Here I'm asking a getLocationPhotos method to get all the photos from Firebase. Notice the observers and completion handler func getLocationPhotos(coordinate:CLLocationCoordinate2D){ dbHandler.getImageFileNames(coordinateIn: coordinate) { (filenames) in if filenames.isEmpty { log.debug(String.warningGet + "filenames is empty") return }//if filenames.isEmpty self.imageFiles = filenames.filter { $0 != "none" } if self.imageFiles.isEmpty { log.error(String.errorGet + "imageFiles array is empty") return }//if imageFiles.isEmpty for file in self.imageFiles { let reference = self.storageHandler.imageReference.child(file) let download = self.imageView.sd_setImage(with: reference) if let i = self.imageView.image { self.imageArray.append(i) self.collectionView.reloadData() }//let i download?.observe(.progress, handler: { (snapshot) in guard let p = snapshot.progress else { return }//let p self.progressView.progress = Float(p.fractionCompleted) if self.progressView.progress == Float(1) { self.progressView.isHidden = true } })//progress download?.observe(.success, handler: { (snapshot) in self.progressView.progress = 1 self.progressView.isHidden = true self.collectionView.setNeedsLayout() })//success download?.observe(.failure, handler: { (snapshot) in log.error(String.errorGet + "Error occured getting data from snapshot") })//failure }//for file }//dbHandler
Swift - Append to NSMutableDictionary
I am trying to append to an NSMutableDictionary with the following code: let RSVPDirectory = NSMutableDictionary() for i in 0..<self.RSVPs.count { var tmp = self.RSVPs[i] var firstLetter = String() if(tmp["lastname"] is NSNull) { firstLetter = ((tmp["email"] as? NSString)?.substring(to: 1).uppercased())! } else { firstLetter = ((tmp["lastname"] as? NSString)?.substring(to: 1).uppercased())! } if RSVPDirectory[firstLetter] == nil { RSVPDirectory[firstLetter] = [AnyHashable]() } RSVPDirectory[firstLetter] = tmp } My problem with this is that I am expecting multiple tmp inside RSVPDirectory[firstLetter] but it only adds the first one as if its overriding the previous tmp How do I append to NSMutableDictionary in swift, I know in objective-c you can do this: [[RSVPDirectory objectForKey:firstLetter] addObject:tmp]; What would be the equivalent to that in swift?
Try the below code in a playground you will see the output, hope this gives you an idea. func upperCaseFirstLetter(_ str: String) -> String { guard let first = str.first else { return "" } return "\(first)".uppercased() } var RSVPs = [[String:String]]() var RSVPDirectory = [String: [[String:String]]]() //Test Data var str = ["email":"test1#c.com"] RSVPs.append(str) str = ["lastname":"Atest2"] RSVPs.append(str) for i in 0..<RSVPs.count { var tmp = RSVPs[i] var firstLetter = "" if(tmp["lastname"] == nil) { firstLetter = upperCaseFirstLetter(tmp["email"]!) } else { firstLetter = upperCaseFirstLetter(tmp["lastname"]!) } if RSVPDirectory[firstLetter] == nil { RSVPDirectory[firstLetter] = [[String:String]]() } RSVPDirectory[firstLetter]?.append(tmp) } print(RSVPDirectory)
This is the native Swift version of your Objective-C-ish code. It uses the Dictionary(grouping API of Swift 4 let RSVPDirectory = Dictionary(grouping: RSVPs) { (dictionary) -> String in if let lastName = dictionary["lastname"] as? String { return String(lastName.prefix(1).uppercased()) } else if let email = dictionary["email"] as? String { return String(email.prefix(1).uppercased()) } else { return "🚫" } }
Yes you are actually replacing the RSVPDirectory[firstLetter], overriding it every time with new tmp. What you are looking for is this: //RSVPDirectory[firstLetter] = tmp //Replace this line with below code let tempArray = RSVPDirectory[firstLetter] as? [AnyHashable] tempArray?.append(tmp) RSVPDirectory[firstLetter] = tmpArray Here I have used a tempArray because we want to mutate the array. Accessing it directly and trying to append new value will in-turn try to mutate an immutable value. So first I have got the array in the tempArray and then after mutating the array I swapped it back in the dictionary with updated values.
leaky listener firebase ios
I am trying to load message box data for chat functionality. The message box is loaded as: override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) if (PFUser.currentUser()!["firebaseUID"] !== nil) { print(PFUser.currentUser()!["firebaseUID"]) self.updateResultArray(PFUser.currentUser()!["firebaseUID"] as! String) } } func updateResultArray(uid: String) { let userName = String(PFUser.currentUser()!["username"]) //print("updateResultArray is getting called") let userhandle = self.firebase.childByAppendingPath("users").childByAppendingPath(uid).childByAppendingPath("rooms").queryOrderedByValue() .observeSingleEventOfType(.Value, withBlock: { roomsnapshot in let enumerator = roomsnapshot.children while let rest = enumerator.nextObject() as? FDataSnapshot { self.roomArray.append(rest.key) } //get the latest message from all the rooms if self.roomArray.isEmpty == false { for i in 0...self.roomArray.count-1 { print("in the room loop \(self.roomArray[i])") let messagehandle = self.messagesRef.childByAppendingPath(self.roomArray[i]).queryOrderedByKey().queryLimitedToFirst(1).observeSingleEventOfType(.Value, withBlock: { messagesnapshot in print("the messagesnapshot child count is \(messagesnapshot.childrenCount)") let enumerator = messagesnapshot.children while let rest = enumerator.nextObject() as? FDataSnapshot { let sender = rest.value.objectForKey("sender") as? String let reciever = rest.value.objectForKey("reciever") as? String //print("sender is \(sender!) and reciever is \(reciever!)") let eventhandle = self.firebase.childByAppendingPath("rooms").childByAppendingPath(self.roomArray[i]).observeSingleEventOfType(.Value, withBlock: { eventsnapshot in if eventsnapshot.value is NSNull { // The value is null } else { let eventAttr = eventsnapshot.value.objectForKey("eventAttributes") as? String let eventDetails = eventsnapshot.value.objectForKey("eventDetails") as? String //print("userName is \(userName)") //print("sender is \(sender)") if (userName != sender!) //for event joinee { let firstname1 = eventsnapshot.value.objectForKey("firstname1") as? String self.otherNames.append(sender!) self.resultsNameArray.append(firstname1!) self.base4String = eventsnapshot.value.objectForKey("img1") as! String self.resultsImageFiles.append(self.base4String) } else //for event creator { let firstname2 = eventsnapshot.value.objectForKey("firstname2") as? String self.otherNames.append(reciever!) self.resultsNameArray.append(firstname2!) self.base4String = eventsnapshot.value.objectForKey("img2") as! String self.resultsImageFiles.append(self.base4String) } let newlineChars = NSCharacterSet.newlineCharacterSet() let evntArray = eventDetails!.componentsSeparatedByCharactersInSet(newlineChars).filter{!$0.isEmpty} self.eventArray.append(evntArray[0]) self.eventdetailsArray.append(eventAttr!) dispatch_async(dispatch_get_main_queue()) { () -> Void in self.resultsTable.reloadData() } } }) // self.firebase.removeAuthEventObserverWithHandle(eventhandle) } }) //self.messagesRef.removeAuthEventObserverWithHandle(messagehandle) } } }) //firebase.removeAuthEventObserverWithHandle(userhandle) } since i am using observeSingleEventOfType i havent coded to remove handlers( i have tried that as well). In the individual chat, the code is like this: func refreshResults() { print("the roomid is \(roomid)") //update from firebase let messagehandle = self.messagesRef.childByAppendingPath(roomid).queryOrderedByKey() .observeEventType(.Value, withBlock: { messageTextsnapshot in self.messageArray.removeAll() self.senderArray.removeAll() // print("the messageTextsnapshot child count is \(messageTextsnapshot.childrenCount)") // I got the expected number of items let enumerator = messageTextsnapshot.children while let rest = enumerator.nextObject() as? FDataSnapshot { let text = rest.value.objectForKey("message") as? String let sender = rest.value.objectForKey("sender") as? String if text != nil && text != "" { self.messageArray.append(text!) self.senderArray.append(sender!) } } for subView in self.resultsScrollView.subviews { subView.removeFromSuperview() } for var i = 0; i <= self.messageArray.count-1; i++ { if self.senderArray[i] == userName { if (self.messageArray[i].rangeOfString(self.acceptMessage) != nil) { let chatBubbleData = ChatBubbleData(text: self.messageArray[i], image:self.myImg, date: NSDate(), type: .AcceptMine) self.addChatBubble(chatBubbleData) } else { let chatBubbleData = ChatBubbleData(text: self.messageArray[i], image:self.myImg, date: NSDate(), type: .Mine) self.addChatBubble(chatBubbleData) } } else { if (self.messageArray[i].rangeOfString(self.acceptMessage) != nil) { let chatBubbleData = ChatBubbleData(text: self.messageArray[i], image:self.otherImg, date: NSDate(), type: .Accept) self.addChatBubble(chatBubbleData) } else { let chatBubbleData = ChatBubbleData(text: self.messageArray[i], image:self.otherImg, date: NSDate(), type: .Opponent) self.addChatBubble(chatBubbleData) } } let bottomOffset:CGPoint = CGPointMake(0, self.resultsScrollView.contentSize.height - self.resultsScrollView.bounds.size.height) self.resultsScrollView.setContentOffset(bottomOffset, animated: false) } }) self.messagesRef.removeAuthEventObserverWithHandle(messagehandle) } There are a few other listeners similar to this. the problem is when i go back from this view(individual chat to message box, the memory consumption increases. I have cleared all arrays and closed the handlers immediately after use. but still memory consumption increases and sometimes in message box same rows are replicated again. how should i solve this. I tried using observeSingleEventOfType but it is not a correct solution as the data sync stops. Used this as reference: https://www.firebase.com/blog/2015-10-15-best-practices-uiviewcontroller-ios-firebase.html
It looks like your message box object is not being released due to a retain cycle caused by the listener callback block holding a reference to the message box object. You can alleviate this by using [weak self] in blocks that you pass to other objects. For example: .observeSingleEventOfType(.Value, withBlock: { [weak self] roomsnapshot in let enumerator = roomsnapshot.children ... This makes 'self' an optional type, and you can then add: guard let strongSelf = self else { ... }
The problem was that i was closing the listeners on the parent and not on the child. so the listeners were still in memory. When i closed the listeners on the full path it worked.