iOS: Is it necessary to remove Firebase observers? - ios

Why should I remove firebase references observers? I'm ok if all references get observed as long as the app is running. I'm not sure if references will still be observed after the user leaves the app, but if memory is only consumed while the user is using the app, why bother remove the observers? Especially if the data is mostly light weight texts.

I've looked into firebase documentation and there is no clear info about it.
There are several snippets saying that is a good practice to remove them on the opposite method you created them.
If you create them on onCreate, remove them on onDestroy. If you created them on viewWillAppear, remove them on viewWillDisappear.
In my experience I found out that is less cpu demanding to just leave them around if they are not firing very often. I have several observers on my app it's less cpu intensive to just quit the app than to remove them.

The case is not what can happen if the user leaves the app, after it's closed/killed it'll not be observed anymore. Neither is a problem because of CPU or internet usage, since you'll get light weight texts. The case is what can happen if the user is using the app and an observable is fired.
Let's say that in your app's home page you'll have an observable sending the user to a specific page if a value on the user's node changes, and if in the middle of the usage this value changes the user may be redirected to another page without knowing what happened, so bad UX.
Something that happened to me was leaving observables and them i signed out of my account, my app broke because there was no user connected, therefore i wasn't able to observe a node where i needed to be authenticated to query a value.
So that's why you should remove every observable as you go off a page or when quiting the app or signing out, because it can give the user some errors or uncommom behaviours that'll make them think that the app is broken or is not a good app.
Hope this helps :D

Related

iOS - Constant listening to database update implementation

I have a project where I have 4 tab bars, and when i switched tabs, my api to get the API request to update my view is in the method viewDidAppear().
However this will make a very bad UX experience for user as whenever they switch tab, a loading icon and some times it load for 0.5 seconds but that instant appearance and disappearance of the loading icon is really bad for UX perspective. How can i implement a view where whenever the database value change, my view is automatically updating itself?
I have thought of using Timer() to implement where it calls the api every second but this is not practical as it will be constantly calling the API every second.
Does anyone have any suggestion? Thank you
There's a lot to unpack here, but I'll try to provide a generalized answer and point to several possible solutions to the UX problem.
There's several aspects that can play a role here:
Do you control the backend the data comes from, i.e. is it possible to follow paiv's comment and implement push notification? Or perhaps use some other means than pure HTTP(S) requests, like a websocket?
How frequently does data change? Is it realistic that it does so in between switching from one tab to another?
On that note, what do you do when data changes while your user is on one tab? Does that get refreshed in any way? Is it a problem if they don't get informed about this immediately? Is there a refresh button?
Do you persist the data beyond a view's on-screen time at all? Is it scrapped when a user re-visits a tab, i.e. does a tab always start "empty" until the API response is handled or do users see the values from the last time they visited that tab?
What best to do depends a lot on the exact answers to these questions. If you cannot enable the backend to do anything besides serving HTTP requests AND have to keep all data up-to-date constantly then obviously you have to do something like the polling you described. The update-interval depends on how important this is for your users. Even if it is 1 second, be aware that this means they could visit a tab before the next update has been fetched.
If you can adapt the backend and up-to-date data is a must, then push notifications or perhaps websockets are a way to go (keep in mind that websockets mean one open-connection per active user then!).
Push notifications would probably break down when the update interval is too high (i.e. if data gets changed in the backend very quickly and you keep spamming them), but would work nicely otherwise, plus they would update views that are already on screen if used correctly.
In 90 % of the cases I've seen, however, going with regular HTTP requests and a properly designed UI is the best choice. Properly decoupling the UI code from the data loading code and the code that displays the data is also very important. Here's how I would handle this:
Properly persist the data in some way in the app that does not require on views owning the data alone. If you want to persist beyond app runtime that means CoreData (or an equivalent), otherwise an in memory storage may be fine (that is kind of a global state then).
In your UI, show any data you currently have, even if it is "outdated" (in your case: "left over from the last time the user was on this tab"). Design the UI so that this is clearly apparent (grey it out, put tiny activity indicators next to the data while it is being loaded anew/updated, or something similar).
As said in 2. do show if the app is loading data. Initiating the loading when the users go to a tab is okay, but don't make a UI that is completely dominated by it (like one giant, empty view with a spinner on it).
Functionally, the loading should not directly update any views, instead it writes new data to your storage and just informs views and view controllers that they need to update themselves (if you're using CoreData and/or Combine you get a lot of this logic basically for free, especially for a SwiftUI app).
Such a design also lends itself to later being adapted for push notifications: While at first the re-loading is triggered by a tab switch (or a "refresh" button, for example), once (silent) PNs are available, they trigger the reloading. Even websockets can be integrated into this more or less, though there's probably a bit more to do that.
In any way, as said it all depends on your use-case and also available resources, but the gist of it is probably "If the current loading icon you have destroys the UX, redesign it properly". My gut feeling here would be that anything else might be over-engineering for your needs...

In iOS11, how to keep a background task running past 10 min?

My question involves keeping an app that monitors user interactions in the background, for example time spent in one or the app. The issue arises when you can not have a background process run for more than 10 min or violate Apple's sandbox restrictions. Since I am relatively new to the Apple API, and could not find a direct answer that didn't involve location services or VOIP (which are both interesting options, but my application will not be able to use either viably), I come to ask for options in which I can understand when another app opens, when it closes, when it fetches data, and when user holds phone in certain orientation (ie when people hold their phone at certain angles to read text and etc.) for certain amount of time.
The purpose of this analyzation is to predict an attention span for the user, so I need to be able to run in the background, as the user will not be using my app while it predicts attention span.
My thoughts on this are possibly accessing the system log, and somehow parse previous statements (I don't think sandbox will allow), but inevitably the iOS system will suspend my processes after some point unless I put a timer. There is also the option of having the system wake up my app via opportunistic fetching, but that won't be useful if I don't collect the data.
Keep in mind this is within IOS 11, so it is much more restrictive than previous iterations. I understand this may seem like a complex problem, but even a direction in which to head could be useful to me.
This solution might work, (not recommended since it drains the battery quicker).
Just update your current location, every 10 mins. It will reset the background thread timer.

UWP/WinRT: How to save and then restore a simple TextBox for resume from termination?

In this document describing the lifecycle of a Windows 10 UWP app, it states:
Users now expect your app to remember its state as they multitask on their device. For example, they expect the page to be scrolled to the same position and all of the controls to be in the same state as before. By understanding the application lifecycle of launching, suspending, and resuming, you can provide this kind of seamless behavior.
However, there doesn't appear to be much documentation on how this is actually achieved. I gather that everything is to be manually saved by the app developer, and then recreated from scratch on resume using whatever data you stashed away when the app was suspending, all in order to create the illusion that the exact memory state of the app never changed.
I'm trying to puzzle through this using just a minimal example, a XAML page containing nothing other than a TextBox. Even this situation, though, I'm struggling a bit to understand how to achieve the goal. I'll provide more general thoughts, but my concrete question simply is how do you save and then restore a simple TextBox for resume from termination? I'm working in C++/CX but will take any help I can get.
Here are my thoughts on this so far:
At minimum, obviously the text of the TextBox has to be saved.
This could be saved into the ApplicationData::Current->LocalSettings.
One issue I see immediately is that the document I cited above on lifecycles states that apps must take care of their saving within 5 seconds of the suspend signal or face termination. A Textbox could potentially hold a lot of data, causing a save to potentially be cutoff in the face of busy IO, particularly if we start scaling beyond the trivial single TextBox situation.
Fortunately, the document states, "We recommended that you use the application data APIs for this purpose because they are guaranteed to complete before the app enters the Suspended state. For more info, see Accessing app data with the UWP app." Unfortunately, when you follow that link, there is nothing relevant there providing any more detail, and I can't find anything documenting this behavior in the API's. By saving into ApplicationData::Current->LocalSettings are we safe from being cut off with corrupted or lost data?
Once the minimum has been taken care of, next we'll probably need extras like cursor and window position.
We can get the cursor position with TextBox->SelectionStart, which as far as I can tell, is undocumented in the API of this usage of returning the current cursor position. This seems an easy fit to also store as an int into ApplicationData::Current->LocalSettings.
How can we get, save, and restore the scroll position of the TextBox window?
Now that we've got the extras, how about the hard stuff, like undo history? I'm assuming this is impossible as my question on Stackoverflow on how to access the TextBox's undo facility has gotten no answers. Nonetheless, it does seem like a poor user-experience if they swap to another app, come back thinking that the app never closed due to the beautiful and seamless restore from termination we implemented, and their undo history has been wiped out.
Is there anything else that would need to be saved for the TextBox to create the ideal user-experience? Am I missing something or is there an easier way to do all this? How would something like Microsoft's Edge Browser handle the complex case where there are dozens of tabs, form inputs, scroll positions, etc. that all need to be saved in 5 seconds?
The App lifecyle document you reference has been updated for Windows 10, but seems to have lost some of the important bits that you are wondering about.
I found an old blog post, Managing app lifecycle so your apps feel "always alive", that seems to be the inspiration for your link.
In the blog post, there is a paragraph towards the end that reads:
Save the right data at the right time
Always save important data incrementally throughout the life of your app. Because your app has only up to five seconds to run suspending event handler code, you need to ensure that your important app data has been saved to persistent storage by the time it is suspended.
There are two types of data for you to manage as you write your app: session data and user data. Session data is temporary data that is relevant to the user’s current experience in your app. For example, the current stock the user is viewing, the current page the user is reading in an eBook or the scroll position in a long list of items. User data is persistent and must always be accessible to the user, no matter what. For example, an in-progress document that the user is typing, a photo that was taken in the app or the user’s progress in your game.
Given the above, I'll attempt to answer your questions:
how do you save and then restore a simple TextBox for resume from termination?
As the end user is typing in the TextBox, the app saves the contents in the background to the data store. To borrow from how word processing software works, you auto-save the textbox "document". I would consider the textbox content to be what the blog post above describes as "user data". Since the save is done outside of suspension, there is no time window to worry about.
When your app resumes from termination, it checks the data store and loads any data into the textbox.
Once the minimum has been taken care of, next we'll probably need extras like cursor and window position.
I would consider these items "session data" and would save them during suspension. After all there is no need to keep track of this info while the app is active. The user doesn't care where the cursor was 10 minutes ago when he started typing - he only cares about the cursor position at the time of suspension.
how about the hard stuff, like undo history?
I would consider undo history to be "user data" and would save it while it is happening (outside of suspension). In other words, as the user types in content, your app should be saving the information necessary to undo.

how to use GANTracker for long running iOS apps, including background audio

My App is typically run overnight as a baby monitor, either as foreground app, or with background audio running.
Goals:
Track total app startups ie. active user count.
Track total usage time in foreground vs background and total session time.
Track various page-views if they navigate the settings screens.
As recommended, I start the tracker in didFinishLaunchingWithOptions, and track my first ViewController as my first 'page-view'. My App might stay on this page then for the next 8 hours...
A couple of issues then appear:
When do I call stopTracker and what does it do? I'm hoping that it terminates the tracking session. But since google kindly hid their code in a static lib, I have no idea what's going on under the covers, and the .h doesn't say much. First instinct is to put stopTracker in applicationWillResignActive however, if the user decides to enable background audio my app is still running...
Next I read that a session can timeout after 30mins with no new pageviews, or at midnight. I could set a repeating timer to send the same page-view every 20mins, that should keep my session alive, at least until midnight, but then my page views are going to be much larger? unless it's smart enough to know I'm on the same page with every call. google analytics blog
[Update: each call seems to be counted as a new pageview, and numbers are thus skewed, so still an issue how to handle this]
If my timer above runs past midnight and the session has expired, I'm going to end up with a new session and double the actual active user count?
If I do call stopTracker in applicationWillResignActive, will the next call to track a page-view restart the tracker? or do I need to call startTrackerWithAccountID again?
If instead I start the tracker in applicationDidBecomeActive, I lose the session that might have been running in the background.
[update: this seems to be the best approach so far, but testing is very slow due to time lag on analytics reports, I will report back soon]
PS EasyTracker doesn't seem to handle this any better.
I got this working by using a pageview called 'Backgrounded', and when the user has selected no background functionality, then instead the app is calling stopTracker. I see multiple hits, with an average session of 20mins, but i can multiple pageview by time to see total time for goal 2. I found two solutions for goal one, events (which were not exposed in easy tracker), and also in my applicationDidBecomeActive (if it's not a restore of backgrounded app) then i track a pageview for AppStarted. I ended up wrapping the whole thing in a utility class and rolled it into a couple of my apps, so will be interesting too see the results. If anyone else tries this, you might want to think about using the custom variables too. I added my app version to this, so I can also monitor how many users are migrating to the latest app releases.

What actions are required when your app get an applicationWillResignActive call?

This question io3->ios4 upgrade said to support applicationWillResignActive. While implementing this call, I also implemented applicationDidEnterBackground and applicationWillEnterForeground. However, I found that my app would crash. After some debugging on the simulator I determined that I needed to reinitialize a key data structure in applicationWillEnterForeground. So my question is how would I have known that from reading the documentation? (In fact, I may be doing the wrong thing and just so happened to get it working again.) Is there an exact description of what to do when these methods are called?
Thanks.
The only things you should do when supporting multitasking, is saving the state of your app when it enters the background, and reload it when it becomes active. (If you generate a new template in Xcode, you'll see this.)
Saving state means writing any user preferences or data to disk. Reloading the state involves reading saved preferences and data, recreating any in memory data structures that might need it (like in your example you gave).
In most circumstances, there's little else you need to do. The only thing that would crash your app that is unique to multitasking would be trying to run code in the background for longer than the allotted amount of time, (which is 10 minutes.) Otherwise, it sounds like you have got other problems with your code.

Resources