Dealing with asynchronous download delays before displaying data - ios

My app connects to a Parse server asynchronously and downloads the necessary data into the app's Core Data store . I would then like to display this data in a tableview. But in most cases -- as the connection is asynchronous -- the table view can access the data store much faster than the downloaded does . In this situation, I get an empty table view cell, and just after that the data is ready in the data store.
What is the best way to deal with the delays caused by asynchronous downloads? Is there a concept that I'm missing? Is it NSFetchedResultsController?

What do you think is the best way to deal with the delays caused by
asynchronous downloads?
It depends on requirements you have. In particular, if the user can interact with UI during async downloads, you can do nothing on it, otherwise you could use just a spinner to alert him something is downloading and stop the interaction until the sync as finished.
Anyway, in both cases, you should say something about the download. In particular, are you saving data in a different thread (different from the main one)? If so you should merge the changes from the context you use in background to the context associated with the NSFetchedResultsController (always the main one since NSFetchedResultsController manages UI elements).
Is there a "concept" that I miss and is it NSFetchedResultsController?
Did you setup correctly the delegate NSFetchedResultsControllerDelegate? If so, the NSFetchedResultsController tracks changes on the entity you registered on your fetch request. Not changes will happen for other entities.

Asynchronous is a design problem that you will need to work with. Look to some of the other popular applications in your field and see how they solve it. Do they show a spinner (I personally hate that) or do they show some unobtrusive indicator that data is being downloaded (better)?
If you use a NSFetchedResultsController (which I am guessing by your question you are not currently) you will get the data displayed once it is saved in Core Data with no additional effort on your part. So you can at least show the data as soon as possible.
In the meantime, I recommend let the cells/table be empty and let the user know that your app is working. Display the data as soon as possible. Perhaps consider downloading the data in pieces so that they can start to see it asap.

Related

Remove Core Data Support From An App On The App Store

I have an app on the App Store, and it is getting a decent amount of use. I'm doing things differently as I release updates, and want to completely remove core data from the application. How exactly do I go about doing that in the next released update?
Do I simply remove all the core data code in the AppDelegate file, and remove the data model file?
I want to be certain no units will crash as the new update is released.
Option 1: just ignore it
This is by far the easiest solution. Just leave the core data files on the user devices and they will just forever take up space for the user. If the amount of data is small (less than 50mb), and the data stored in them has either already been transitioned or doesn't need to be, then this is a good option. You can remove all reference to core data from your app.
Option 2: delete it in the background
You can delete it in the background when the app first runs. Make a background context, fetch all objects, delete them, and save. When done mark that it is done in NSUserDefaults and don't do it again. If the amount of objects is very large it might require more complex code of batching the fetches and deletes. You need to retain at least the core data model, and possibly much more, in order for the delete to work.
Option 3: transition the data
This is the hardest option because transition the data can take time, and if it takes too long iOS will force quit your app. So first present a view controller explaining the user what is happening - and perhaps a progress indicator. Then fetch the data in batches, save to you new store, delete it, and update your progress indicator. When all the transition is done, then update your view controller. Here you might need to retain a large amount of core-data code just to deal with this transition.

How to structure the network requests on an iOS App

So, I'm still an unexperienced developer and I need some help with an app I'm currently developing.
The app consists of different tab-views. The first two of them rely on data that is stored on a database. The first database I created myself with Firebase, because it is a news-section, which I need to update regularly myself. The second tab-view needs to request simple data from two different databases, which both return data in the JSON format. The App then should save the data of both databases as custom objects in two different arrays, which both will be used to compare the data sets and display some of the data in a table view.
The thing I'm struggeling with is where to trigger those network requests without compromising the user's experience. What is the best practice to do so? At the moment, the first network request is in the viewWillLoad() method of the associated viewcontroller. But I'm not quite happy with that because there is a small delay between opening the app and displaying those news. Additionally is it better to download the data and then save it locally on the device and compare it to the data online or to download it everytime? It's not a lot of data and just text - no pictures, videos whatsoever - and little pieces of the data change regularly and most of the data changes only twice a year)
Thanks for helping me out here, because I somehow did not find a lot of information on how to structure those requests and I hope that some more experienced programmers might be able to help me here.
You can kick off network tasks in your AppDelegate in:
func applicationDidBecomeActive(_ application: UIApplication) {
}
Just make sure you throttle it so you don't do it too often.
Generally, you want to cache/store your network results and display the cached values. This is especially important if the user is in an area with limited or no network availability when they launch your app.
If you're using CoreData then updating the data will update your table view automatically. If not, then you can call reload() on your table view in the completion block of your network update, or post a notification that your view controller is listening for, and update then.
Either way be sure to update using a URLSession data task on a background queue.

Download, save to Core Data, fetch and Display? or download, display and then save?

I'm building an app that gets posts from a WordPress blogging site and display on a tableView. Each table view cell displays the post image, title and excerpt text. That's a course project, and use of Core Data is required. So my question is, for a better user experience, should I display the image on the cell straight after downloaded and then save to the Store or should I save to the Store, fetch, and then display?
Some considerations:
when the app launches it will check the internet connectivity, if the connection is establish, the store will be cleaned and the latest post will be downloaded.
It will download 5 posts at a time
Scrolling up will perform the download of older posts.
This is a opinion oriented question. The best I can do is to let you know how I design my apps to deal with this case in the past.
My solution :
Use NSFetchedResultsController to read the data from core data and use the NSFetchedResultsController's fetchedObjects array as a data source to your UITableViewController or UICollectionViewController
Implement the delegates of NSFetchedResultsController which will get triggered when data in Core data changes. This way u can efficiently update your CollectionView and TableView and show the data changes on UI ASAP.
Use Background Contexts to modify the data that way your main thread will be free and application remains responsive.
In order to create Background Context, I prefer parent child context architecture rather than traditional multi context architecture. parent child context architecture is easy to understand, keeps the code clean.
Never save image into core data. Instead save the image downloaded to document directory and save the relative link to the downloaded files in CoreData.
Remember I said relative path to deleted file not the absolute file. Because your application folder/sandbox path changes on killing and relaunching the app. Saving the absolute path to the file in core data is a perfect recipe to screw up the logic.
Don't worry about the delay in saving data to core data. The delay might be in fraction of second which you won't even notice. Saving the data in a array and then fetching the data from core data and updating array is a complete no.
Personally, using an array to save data instead of NSFetchedResultsController's fetchedObjects is a complete NO. why ? Simple, Array is not thread safe, because you will background thread to make web service call and parse data you might have multiple threads accessing Array simultaneously. Because Array isn't thread safe, you might easily get into state of data inconsistency and might lead to crash as well.
Finally use libraries like SDWebImage to efficiently load the image. SDWebImage will not only loads the images but also caches them at various levels (In RAM and HardDisk as well) there by loading images fast and swift.
If you are planning to use pagination to fetch data, use scrollView's delegate of scrollViewDidScroll to figure out when user scrolls to bottom of the table/collectionView and make web service call and fetch data in background thread update core data. As soon as you update mainObjectContext NSFetchedResults controller's delegate will be triggered and you should be able to update the UI immediately.

Is it acceptable to load Realm objects in the main ui thread?

we are adopting (Swift)Realm as a data store in our iOS app and we are really pleased with it so far. We have a question around the design for the retrieval and storage of objects with Realm and multi-threading:
Is it acceptable to load objects in the main ui thread?
We know about the constraints that objects loaded with realm cannot be shared between threads.
We are also not seeing any performance issues yet, but our approach so far is to load all kinds of resources in background threads.
In the case where we load and filter some data and register a notification block, we don't see problems with using the main ui thread, but how would we handle a situation, where we for example want to display all data in a table view?
Is it acceptable to load objects in the main ui thread?
Yes, it is in most cases* acceptable and fast enough. It wouldn't be acceptable if reading from the database would block the user, but as there is no concept like faults, read access is always predictable fast.
Only if you have a really complex object graph, where you need to do heavy pre-processing to be able to display the objects on the UI, it would make sense to employ a background thread and/or caching to warrant a good user experience.
In the case where we load and filter some data and register a notification block, we don't see problems with using the main ui thread, but how would we handle a situation, where we for example want to display all data in a table view?
A UITableView only request those cells which are currently visible on the screen and reuses the view containers. A Realm collection is similar in this lazy nature, when you don't filter it, it doesn't enlarge the memory pressure, because you get only object accessors for those objects which you pull out of it. There is no need for pagination as long as you rely on the builtin Realm Results or List collections. Only if you need to apply a custom and complex filter in a way which isn't supported by Realm, it might be necessary to process that on a background thread.

CoreData in-memory setup with MagicalRecord 3

Hello I'm using CoreData + MagicalRecord 3 to manage the data in my app. Until then everything was working fine, but then I realize in production than my app is freezing like hell !
So I started to investigate knowing about the fact that to not stuck the UI, it's better to have a main context and a background context and save stuff in background etc...
Nevertheless I have to question due to my setup. I use CoreData in-memory store system (for the best performance) and I don't care about storing the data on disk of my app, I'm fine with a volatile model that will be destroyed when the app is killed or in background for too long. I just want to be able to find my data from any view controller and without coupling.
So I have few questions :
1) If I would use 1 unique context, what would happen if I NEVER save it to the memory store ? For instance if I MR_createEntity then I retrieve this entity from the context and update it, is it updated everywhere or do I have to save it so it can be updated ? In other term was is the interest of saving for in-memory where you don't want to persist the data forever ?
2) If I use 1 unique context that I declare being background, if I display my screen before my data is finished to saved, the screen won't be able to find and display my data right ? Unless I use NSFetchResultController right ?
1) you want to save your data even with an in memory store for a couple of reasons. First, so that you can use core data properly in the case where you might change your mind and persist your data. Second, you'll likely want to access and process some data on different threads/queues. In that case, you'll have to use Core Data's data safety mechanisms for threads/queues. The store is the lowest level at which Core Data will sync data across threads (the old way). This may be less important if you use nested contexts to sync your data (the new way). But even with nested contexts, you'll need call save in order for your changes to merge across contexts. Core Data doesn't really like it when you save to a nil store.
2) You can make and use your own context for displaying data. NSFetchedResultsController does a lot of the leg work in listening for the correct notifications and making sure you're getting very specific updates for the data you asked for in the first place. NSFRC is not always necessary, but will certainly be the easiest way to start.

Resources