iOS - How to disable the Firebase caching? - ios

I made delete on post object in firebase node.
But when I query for post objects , previously cached post objects are shown.
I am not getting refreshed data from firebase.
Question:
Is there a way to stop firebase caching and get the refreshed data from firebase in iOS?
MY Code:
self.firPostRef.child(userID).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.value is NSNull { completion(nil) }
else {
//print(snapshot.debugDescription)
let postids = Array((snapshot.value as! [String:AnyObject]).keys)
print(postids)
completion(postids)
}
}) { (error) in
debugPrint("error occured in getting all comments -" + error.localizedDescription)
}

use observeSingleEventOfType, reference.keepSynced(true). It refreshes data once this code is executed.
Use observeEventOfType. This will always keep your data in sync and will execute again as soon as you made changes.

Solution :
Just disable the firebase caching using the following code:
FIRDatabase.database().reference().keepSynced(false)
Ta da ..

Related

Apple Core Data saving duplicates of entities when initializing entities

I am currently building an iOS app that utilizes Core Data to cache Firebase queries, so that my app won't be hitting the Firebase server multiple times for the same query.
My main issue right now is with fetching what will be labeled as IdeaEntity, where the initial fetch will result in the published array of IdeaEntity storing duplicates of the IdeaEntity elements. I will post images below, along with the code snippet for how I'm fetching IdeaEntity arrays from Core Data. However, when re-opening the app (when you close it down via app preview), the duplicates seem to disappear.
iOS Simulator 16.2; Showing proof of duplicate IdeaEntity
// Fetch either from Firebase or Core Data
func fetchIdeas() {
let request = NSFetchRequest<IdeaEntity>(entityName: "IdeaEntity")
do {
self.savedIdeas = try appContainer.viewContext.fetch(request)
if self.savedIdeas.isEmpty {
self.initialFetchIdeas()
}
} catch {
print("ERROR - \(error)")
}
}
// Initial Function to fetch IdeaEntity
private func initialFetchIdeas() {
do {
let uid = self.firebaseService.fetchUserID()
guard !uid.isEmpty else { throw AltyrErrors.cannotFetchUid }
self.firebaseService.fetchUser(withUid: uid) { [weak self] user in
guard let self = self else { return }
self.firebaseService.fetchIdeas(user: user) { ideas in
guard !(ideas.isEmpty) else { return }
ideas.forEach { idea in
let newIdea = IdeaEntity(context: self.appContainer.viewContext)
// ... Insert code for inserting parameters for `newIdea`
if let feedback = idea.feedback {
let newFeedback = FeedbackEntity(context: self.appContainer.viewContext)
// ... Insert code for inserting parameters for `newIdea` Feedback object
newIdea.feedback = newFeedback
}
}
self.save()
}
}
} catch {
// TODO: Error handling...
print("ERROR - \(error)")
}
}
Couple of assumptions:
FirebaseService functions are assumed to be 100% functional, as in they output the needed items in a proper manner.
The above functions are in a class named CoreDataService, which is a class that inherits from ObservableObject
savedProjects is a Published array of IdeaEntity
If there is a better manner of fetching with another library, a different method for fetching IdeaEntity, need any other code snippets / signatures, or anything else, please do let me know.
I had tried switching around fetchIdea with initialFetchIdeas within the private init (since CoreDataService is a singleton) to see if fetchIdea was missing anything that initialFetchIdeas had, though the result is the same (e.g., duplicate entities).
Edit: TL;DR of the solution, just use NSCache if you have really complex objects. It's not worth the effort to utilize Core Data.

SwiftIU/Firebase: How to update lists of users from Firebase in real time and have it reflect in the UI?

https://www.loom.com/share/de410c2626644dd796ad407fcee7e5c7
^^^ I've attached a loom video demonstrating the bug im facing as well as the code I currently have.
The problem is that the UI doesn't update right away and may confuse users. All the code in terms of updating the backend function correctly (its the updating of the UI thats not working properly), I'm pretty sure it has to do with the way i'm either calling the functions or the function itself.
Any help would be greatly appreciated!
#Published var userRequestInboxUsers = [User]()
#Published var emergencyContactUsers = [User]()
// function to fetch the user requests
func fetchTheUsersRequests() {
guard let uid = user.id else { return }
let query = COLLECTION_FOLLOWERS.document(uid).collection("inbox").whereField(
"currentStatus", isEqualTo: "isPending")
query.addSnapshotListener(includeMetadataChanges: true) { snapshot, error in
if let error = error {
print("There was an error querying the inbox requests: \(error.localizedDescription)")
} else {
for request in snapshot!.documents {
COLLECTION_USERS.document(request.documentID).getDocument { snapshot, error in
if let error = error {
print("There was an error fetching the user data: \(error)")
} else {
DispatchQueue.main.async {
guard let userRequestInInbox = try? snapshot?.data(as: User.self) else { return }
self.userRequestInboxUsers.append(userRequestInInbox)
}
}
}
}
}
}
}
//function that fetches the users contacts (request that have been approved)
func fetchTheUsersContacts() {
guard let uid = user.id else { return }
let query = COLLECTION_FOLLOWERS.document(uid).collection("inbox").whereField(
"currentStatus", isEqualTo: "emergencyContact")
query.addSnapshotListener(includeMetadataChanges: true) { snapshot, error in
if let error = error {
print("There was an error querying the emergency contacts: \(error.localizedDescription)")
} else {
for userContact in snapshot!.documents {
COLLECTION_USERS.document(userContact.documentID).getDocument { snapshot, error in
if let error = error {
print("There was an error fetching the user data: \(error)")
} else {
DispatchQueue.main.async {
guard let userEmergencyContactsInInbox = try? snapshot?.data(as: User.self) else {
return
}
self.emergencyContactUsers.append(userEmergencyContactsInInbox)
}
}
}
}
}
}
}
I've tried calling the function every time the view appears but that leads to duplicated results.
I'm currently using snapshot listeners to get real time access but even then this doesn't work.
I've structured my backend to have a contacts sub collection and a requests sub collection but I get the same problem with much more lines of code...
I've thought of switching to async/await but i would prefer my app be compatible to ios 14+ rather than just 15 and up.
I could try using strictly Combine rather than call backs but I don't think that would be effective in attacking the problem head on.
The problem is that you're appending the documents to the published property. This will lead to duplicating the entries.
Instead, just assign all of the mapped documents to the emergencyContactUsers property.
Check out Mapping Firestore Data in Swift - The Comprehensive Guide | Peter Friese for more details about this. I've also got a number of other posts about Firestore and SwiftUI on my blog that might be useful.
As for the "duplicate IDs" warning you see - that might actually also contribute to the issue. SwiftUI lists require all list items to have a unique ID, and it seems like your user objects might not have unique IDs. This might either be due to the fact you have multiple copies of the same user in the published properties, or that your User struct is not identifiable.
I noticed that you're using DispatchQueue.async to make sure you're on the main thread. This is not necessary, as Firestore will make sure to call your code on the main thread. See https://twitter.com/peterfriese/status/1489683949014196226 for an explanation.
Also - I am curious about what you said in the beginning of the video about not being able to find documentation about this. We're always looking for ways to make the Firebase docs better - what did you look for / what didn't you find?

iOS firebase observer delays observing the changes in the node

I have one function to get the realtime location updates of the selected user.
And in that function , i need to call the current status and history of that selected user from the firebase.
So, the problem is when I start my observer for location updates only , it's fine and it's great .
I get the value from firebase observer.
But , when i make a call for current status and history of that selected user , I am getting the delay in my firebase realtime observer .
I don't understand how come call to another firebase is affecting our realtime observer code.
Guys any suggestions,
I tried dispatching to background for current status /history call but still no luck.
Left me hopeless and clueless.
Added:
I am getting current status and realtime observers from the same node.
So , does this happens that same node is observing and same time if another firebase call is made to same node , is it colliding ???
UPDATED
Firebase function to get current status :
FIRDatabaseReference().child("personal").child(userUUID).child("realtime")
.observeSingleEvent(of: .value, with: { (snapshot) in
//print(snapshot.key)
if snapshot.exists(){
let location = LocationParser(dict: snapshot.value as! [String : AnyObject])?.location
completion(location)
}else{
completion(nil)
}
}){ (error) in
completion(nil)
debugPrint(error.localizedDescription)
}
Firebase function to observe location (continuously):
FIRDatabaseReference().child("personal").child(userUUID).child("realtime")
.observe(.value) { (snapshot:FIRDataSnapshot) in
print("\nOBSERVER FROM FIREBASE FIRED")
if let value = snapshot.value as? [String:AnyObject] {
if let location = LocationParser(dict: value)?.location {
//we cannot save location to our database
//sharedFirebaseManager.saveLocationHistoric(LocationParser(dict: value)!)
result(success(location))
}
}
}
QUESTION:
I am calling both from the same controller and I see continuous observer delays on calling another firebase function call.
Any clue.

How to synchronously retrieve PFUser objectForKey in Swift

I am trying to synchronously retrieve a PFUser object information. However, I've tried using fetch, but I keep on getting implementation errors. I would like to find for example: PFUser.currentUser()?.objectForKey("scoreNumber"), but I am not getting the updated value. I was told I would find it using fetch, but I am unable to implement objectForKey in my fetch function.
Some of the attempts
var score: String!
func retrieveScore(){
guard let myUser = PFUser.currentUser() else { return }
do{ let data = try myUser.objectForKey("scoreNumber")?.fetch()
try scoreNumber = data! as! String
}catch{}
}
Another one
let userScore = PFUser.currentUser()?.objectForKey("scoreNumber")
let userScore2 = userScore.fetch()
You shouldn't save the user for NSUserDefaults. Parse SDK does a good job of managing your sessions for you. Just have a specific log out button that calls the [PFUser logout]` function.
So, fetch is an asynchronous operation. This means that it runs on a separate thread, and then the main thread will continue executing the next commands. So, you're calling fetch, which fetches an object in the background, but then you are trying to access a value from the object that hasn't been fetched yet. You need to access the object from within the block handling the results of the fetch call.
When you call fetch the way you did, just with .fetch(), it runs in the background but doesn't alert you when you have the data, nor if the fetch failed. This is not a good way to get data you're going to need immediately.
You need to use fetchInBackgroundWithBlock()
scoreNumber.fetchInBackgroundWithBlock() {
(scoreNumber: PFObject?, error: NSError?) -> Void in
if error == nil && scoreNumber != nil {
print(scoreNumber)
} else {
print(error)
}
}

NSMutableArray doesn't save Objects out side .observeEventType from Firebase api

My project is using https://www.firebase.com as backend for a Swift app.
I tried to addObject to my NSMutableArrayvariable in order to use it for my table cell.
So I can retrieve data correctly inside .observeEventType() from the Firebase API but outside that my NSMutableArrayalways empty.
Here is my code
// Create a reference to a Firebase location
var bidRef = Firebase(url:"https://xxxx.firebaseio.com/xxx")
println("firebase test")
// Read data and react to changes
var handle = bidRef.queryOrderedByChild("tableCurrentPrice")
.observeEventType(.ChildAdded, withBlock: { snapshot in
self.pubDataArray.addObject(snapshot.value)
println(self.pubDataArray[0]["tableCurrentPrice"]) //Return Optional(Value)
}, withCancelBlock: { error in
println(error.description)
})
//bidRef.removeObserverWithHandle(handle)
println(self.pubDataArray[0]["tableCurrentPrice"]) // Error empty array
println(self.pubDataArray.count) // Return Nothing
Anyone knows how to fix this?

Resources