iOS - Constant listening to database update implementation - ios

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...

Related

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.

When to refresh data in iOS

I'm not sure this question is strictly limited to iOS, as it's more of a general application-design question on data integrity. But at the moment, I'm getting into iOS and have hit a "best practice" wall.
If we use the Twitter app as an example. We have one tab for our timeline and one tab for our profile. So (to keep things very simple) each one is a View Controller, backed by an object (model). I tweet on the timeline VC, then I head on over to my profile tab. Both viewDidLoad methods have already ran, so the data that was loaded to draw the UI is currently stale. The "count" of my tweets is now out of date. In the iOS world, what is the best methods/approaches to keeping the VC model data synced with the backend?
Is it on a time interval? Or network requests in the viewWillAppear method? Is it event driven, ie. when I tweet in one VC, and it's been saved in the backend web service, I notify any VCs that care that there's a new tweet
I'm not 100% sure this question will have an "answer" in the SO sense, but I'm just trying to understand what's the done thing in the iOS world (as someone who comes from the web development world).
Here's a loose sketch of some things our team has done on a networking application that might give you insight for your own architecture.
At the level of the VC (in viewWillAppear) we typically have multiple NSNotificationCenter observers that will call whatever update methods you need to run after a network update call.
Firing off these notifications is some network listener that lives on a background thread. It's job is to wait for responses from the backend server (typically JSON blobs) that contain updates to the data model. I believe ours has a time interval that will periodically phone home and check to see if we have new things to update.
Note you will necessarily have to devise an asynchronous solution for network calls as the passing/receiving of data packs can be unreliable, and take time, and thus should be computed in the background. You'll also need a way to handle data loss and other errors between server and device. And of course in order to see UI updates, you'll need to switch back to the main thread when updating the VC.
Assuming a some change of state (i.e. new message), then it makes the call to get the new data, which then fires off an NSNotification (with a new payload of info), that goes to the observer on the VC.
As you mentioned with viewWillAppear, UIViewControllers are a core building block of iOS apps. They have a lifecycle to follow to help with things like this scenario.
You have many options, but the best practices would to make calls on the viewWillAppear method and then reload your table views, collection views, etc.
Another thing you can add is push notifications on data change. You can now send a push notification with the "content-available" option that is silent and sent to your app when data changes on the backend. Then your app can refresh data only when needed.
I would stay away from timers. They will keep making network request and keep the radio from going into a battery saving idle mode.

Use of Global Model in ios APp

I am designing an app which manages a tank of hot water. The app makes RESTful API calls to a service to;
Obtain a profile of temperature at various layers in the tank.
Allow a user to work with a timer (like an immersion timer) custom control to set times to turn on/off heating elements.
So, as a first cut, I have two tabs in a nav controller;
1. A graphic, showing a picture of the tank, graduated to show temperature.
2. A custom control, like commercial domestic timers, with two concentric rings, allowing the user to point, and drag 30 minute slots to set times for heating elements.
I have both custom views working well. I'm afraid to say I'm stuck on a very simple point - even after reading all of Apple's ios docs, and would love some help.
The data server (A BeagleBone running embedded Linux) implements 2 sets of RESTful APIs, one dealing with tank temps, and the other set to read and to update timers.
Is it best to start the App with a view controller which instantiates a model, who issues the APIs, and displays "Loading...", then populate a single application wide data model.
Have each view controller (The image of the tank, and the timer controller) to populate their own (separate) model?
And the big question for me (despite years of working in Smalltalk, C++, Java...) what is the recommended way to ;
instantiate a view controller
load / display a view with a "busy"spinner if the model hasn't loaded
My app isn't complicated enough for GCD, or indeed KVO. This is basically, a "show a view, call a web service to read the data", "modify the data", "call a web service to replace the data"
Basically, I believe my question is, when a view comes on screen, what is best practice to determine that the controller has a model, or has a model which is still loading data?
Sorry for the long winded question.
You asked a very good question, about a very common task in an mobile app. My suggestions are
Since your two tabs really have no common data, the problem simply boils down to "how to initialize a view controller with remote data".
If user can't use your app without remote data,
simply show a loading view in [vc viewDidLoad], and start fetching data from server asynchronously; your vc should implement NSURLConnectionDelegate to listen to call back
when data is successfully fetched from server, dismiss the loading view, and render the data to user
if data fetch failed (due to bad network or server downtime), show alert view to user, and retry the data fetching; if fetching fails for several times, tell user to try again later
you can make the loading view more beautiful, to provide a better user experience; note the loading view should cover all the buttons/controls, so user can't mess up your app state during data fetching
If user can use your app without remote data, it's another story. You shouldn't use a loading view in that case, and should silently fetch data in background. Since this does not seem to be your case, I will not complicate the answer by this case.

IOS Saving State For Complex Apps

I'm building a fairly complex business application on the iPad IOS 4.2: 4 tabs, with potentially deep navigational paths on each tab.
In the opinion of some of your more experienced IOS developers, what would the general expectation of a user be with respect to saving application state between launches (i.e. after an app's been fully terminated and subsequently restarted)? I'm using Core Data and have all the data issues covered, but I'm concerned about the application's navigational tree. If the user had left the 1st tab on screen 3, the 2nd tab on screen 4, the third on screen 2, where he left the entry of a new record half-complete, and was, at the time of the app entering the background, working on the 4th tab on screen 3...do you think the average user would expect the application to remember all that the next time it launched? (My gut says yes, though I'm unsure for how long.)
If the answer is yes, can you suggest a general strategy for handling this (and, again, I'm talking about the navigational tree here, not Core Data stuff)? For example, if navigational controllers were used as the root view controller for each tab, it would be simple enough to record enough info about their navigational stacks to be able to restore them later. But what about things like popovers, alert/action sheets, or modal VCs created on the fly? Should each view controller record the state of its UI objects and, if so, what is the recommended way to do this?
I know a lot of this is up to the user, but I'm asking for the general perspective on these issues, i.e. the voice of experience.
It's pretty simple in principle, but it can get quite complex in practice, to go through your navigation hierarchy and storing stuff that can't be derived from the data model.
There's an open source implementation of this called DTResurectionKit. I also documented how I do it in my apps on my website. It's similar to (but simpler than) DTResurectionKit.
In the opinion of some of your more experienced IOS developers, what would the general expectation of a user be with respect to saving application state between launches?
The best way to think about this is to make sure the user never has to figure out why or how they got to where they are when the app first opens.
This depends completely on the type of app you have and the length of time since the last open. It sounds like you have a fairly complex drill-down app so I think it is definitely best to remember the navigation stack, within a pre-determined time frame. I use the three20 framework which does this automatically for me, but if you were to implement it, it would be something like this:
If the user opens up in the past 24 hours, open to the exact spot the left off
If the user opens within a week, open to the main "section" or area of the app they were in
If the user opens after a week has past, open to the root screen.
Now of course, these values will differ based on your apps function and use cases, but you get the idea. By you making some broad assumptions about how people are using your app and when, you can increase the user experience by not shoving them so deep in your app when they won't remember how they got there.
As for implementation, it is all just data.. You dont need to serialize live objects to store the stack, just implement the data needed to recreate the state on the next launch. What you need to store is highly dependent on your own setup... mileage will vary. I use NSUserDefaults to store all instance vars and the navigational stack through Three20. Check out TTNavigator for a great implementation.
I would suggest keeping the state of each tab view. Only at the "page" level. Don't worry about popovers or incomplete data entry (hopefully there's not too much interim state before you're saving it to your core data store.)
Like you said, it's easy enough to remember what tab you're on, and what controller you're navigated to in each tab. More isn't necessary.
It sounds like you've got it under control, but for the benefit of others: 1) when you change tabs, save "active tab", 2) when you navigate within a tab, save "active controller in tab", 3) when you launch the app, set the "active tab", 4) when you change tabs, set/confirm the "active controller in tab".
The reason for 4) is that the view/controllers for the tabs will be delayed in their loading, or perhaps never loaded. You don't want to set the "active controller in tab" for a tab that is not visible and may never be loaded into the app, it would just cause unnecessary loading. It will often happen (after the app has been loaded) that you don't need to change it because it's already in the correct state.
I think your time is better spent elsewhere. Of course, your app might be perfectly suited for this, but in our case data was partly online, could have gone stale, influenced view state in different navigation views in different tabs simultaneously, etc. etc. It's not an insurmountable challenge, but definitely hard and a huge time-sink.
We decided to spend our time on fixing the bugs and improving functionality. If you have to make the same kind of choice, I'm pretty sure which option your users would prefer. Particularly now that your app will survive a phone call in the background.

Best way to load distant data

I'm currently developping an iPhone app and need your opinion.
First, I am developping it for a Football (soccer) Club. It contains many tabs (at least these ones) :
News (Where I am displaying last news posted, obviously)
Shop (Where the user can buy stadium seats, and maybe various goodies)
Don't know yet exactly (But it will be related to Facebook/Twitter or stuff like that)
For every of theses tabs, I need to download XML data (using initWithContentOfURL). Right. But, that's where my problem is. Should I :
Load every needed xml pages at application start-up, and display a nice loading screen ?
Load every needed xml pages at the exact instant the user needs it in the application ?
In the first case, I get a slower application startup, but then, a faster navigation between tabs.
In the second case, my application starts relatively faster (still needs to load News XML, that's the welcome tab), but switching between tabs won't be as fluent as the first case (only the first time the tab is opened, of course).
Any advice?
Take a look at ASIHttpRequest which does provide some pre built caching mechanisms for you that may be appropriate and generally make interacting with web services easier
Load only what you need when you need it.
Furthermore, I wouldn't use initWithContentsOfUrl. It's a synchronous call, and it will lock your app. Instead, use an NSURLConnection to get the data asynchronously.

Resources