What is the most effective workflow for this iOS app? - ios

I have an app that requires internet for syncing a webservice to a local core data db. Then a local db fetch is used to populate different objects for a MapView and a TableView in a tabbarcontroller. Im looking at these 2 scenarios:
The main advantage of "A" is that I dont have to preload the app with a database, although its a small db (about 100 records). The problem is that it gets convoluted. If there is no internet connection, in MapView, the user sees a map but the refreshButton is disabled. So thats not a problem. But the user can still go to the tableview and he will see an empty table.
The main advantage of "B" is that with a preloaded db, the app will always have a data source ready for plotting and listing. I dont really know how to preload the app with a db though.
I kind of want to go the first route, "A". My main question is, since right now I disabled the refreshButton on MapView so that it only works once the data is gotten from the web...that sortedArray is empty on launch. So if the user goes to the TableVC it will be empty. As it stands, the user must first tap the refresh button before going to the tableview.
What is the most effective way to deal with this?

If the 100 records are static enough that you can ship a default set of records with the app, that would be the best solution. The user, with or without internet, gets a populated tableview.
Ship your records as a plist in your app's bundle. On first launch, open the plist and add each entry as a new object into core data. This type of "seeding" happens very quickly. Just create a collection (array, dictionary) for the plist, then enumerate through, mapping it to your managedObject's attributes.
There's code that shows you how to do this in the WWDC 2012 video iCloud and Core Data (just ignore the iCloud part).
Then if there's a connection after the seeding, you can sync data, which would update/replace/etc the pre-populated data.

Related

When to Persist Object Graph

I have an object graph which represents the state of my (first) iOS app. I've implemented NSCoding for each of the objects so I can use a keyed archiver. I have the archiving and dearchiving working fine. But I'm left with a rather basic question: When should I archive things?
Is it safe to only call it when I get an applicationDidEnterBackground message from my app delegate? Or should I pesist things everytime the user does something "significant" in the interface (like dismiss some view where data was entered, etc.)? What are the best practices for this?
I found the answer to my own question in this document:
https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforHandlingAppStateTransitions/StrategiesforHandlingAppStateTransitions.html
Here is the relevant quote:
Important: Always save user data at appropriate checkpoints in your app. Although you can use app state transitions to force objects to write unsaved changes to disk, never wait for an app state transition to save data. For example, a view controller that manages user data should save its data when it is dismissed.

Core Data Values Accessed by Multiple Users when logged in (iOS Swift)

I have an app where a UITableView is used to represent a friends list. Now, this table is updated by values stored in core data, and I'm downloading friend values to core data via Parse. Instead of accessing Parse to update the tableView directly, I decided to update Core Data and then the tableView because I need the friend information in other parts of the app, and thought it would be more efficient to use Core Data than to have calls to Parse again and again. Everything works fine!
However, my app has a log in system before users can use the app. And when I created another dummy user to test it, I found that the friend values stored in Core Data by my actual account were being used to update the friend list tableView! When actually the tableView should be empty (new user).
I don't know exactly how Core Data works but I figure it uses some segment of the device's memory to store entities. My question is this, is it possible to use Core Data to store private information related to a particular user that can't be accessed by other users that log into the same device? Or should I continue to make calls to Parse whenever I need information?
Hope you guys understood my question, thanks!
iOS is not a multi-user system. Your app stores its files in a sandboxed folder structure and this sandbox is independent of any user logins you have implemented in your app.
When a new user logs in (or, if you prefer, when a user logs out) it is up to you to remove any data you have stored in Core Data that you don't want another user to have access to.
Parse can save data offline by Local Storage or cache the request by Cache Policy
They are much faster than creating your own database (by CoreData).

Saving large amount of data from Firebase

I actually sizeable amount of data that I retrieve the entire data from Firebase when the user log into the app, or to the different view controllers which require the data from Firebase.
However, I find it meaningless to continuously retrieving the same data as the user navigates through the app. Is there a way for me to save all the data to the phone upon first retrieval after log in and just refer to the local data whenever I need it?
I have used NSUserDefaults for small amount of data but I don't think that it is the right option for my situation.
For these data, I would also require to search them by key when necessary.
You can use any Database such as CoreData, Realm or SQLite(many wrappers available on cocoapods).
You can find difference between the three on on this blog link.

How to ensure data consistency and truly take advantage of Core Data?

I've worked on several iOS apps, some of them utilize Core Data, and some of them don't. While I consider myself having a basic to somewhat good understanding of Core Data, there's always something that makes me doubt the usefulness of it. I've done a lot of reading on the subject, and the general consensus seems to be the advantages of using it outweighs the disadvantages. I recently submitted an app without using Core Data, and always planned on going back to update the project to utilize it when I have the time for some optimization work. Now's the time, but I wonder if it makes sense for the app I'm working on, and maybe I am not using it correctly all along. Please advise and point out what I am missing.
The project I am working on is a social networking app, which also has a front-end site. We have standard features like a newsfeed, event listing, the ability to follow/unfollow someone, and a map with POIs at user's location. Currently, we're using pagination whenever needed when requesting data from server.
My understanding of why Core Data is great:
Easier to manage data with complicated relationship
Easier to access data without having to pass them around
Easier to manipulate, fetch, and sort your data
Better memory utilization
Improve perceived performance by preloading data stored locally until latest data's received
The problem I am having is, since I am using pagination when requesting for data instead of requesting for all at once. The data stored locally is only a subset of the current state in the database. Let's use newsfeed as an example. If I do the following, it will cause some problems:
User manually refresh the newsfeed -> Controller notifies model that it needs the latest 20 items -> Model requests for the latest 20 items in the newsfeed and save them as NSManagedObject -> Model notifies controller that data is ready -> Fetch the latest 20 items to show in UITableView
If user A refreshes the newsfeed, background the app, and then user B deletes his post in the newsfeed (let's say it was 10th item) before user A foregrounds the app again to refresh the newsfeed. In user A's newsfeed, B's post will still be up there because according to the createdAt attribute, it's indeed one of the latest 20 items.
To fix this problem, I can think of a few solutions:
Add a flag to the item to indicate it's removed
Always discard local data when new data arrives
Disable pagination
Instead of using the workflow described above, always present the requested data only instead of fetching the latest
Solution 1 means custom code is required to deal with different clients since browser doesn't need deleted items but iOS client does. However, even though it can work, it can potentially mess up the pagination mechanism and can cause weird behaviours in the client. For example, if a large amount of items gets removed, the latest 20 items will contain only a few items that will actually show up in the newsfeed on the client when user refreshes it. As user follows more people, more stories will be inserted in his newsfeed as well. This solution won't work very well in this situation.
Solution 2 totally defeats the purpose of using Core Data in the first place unless I am missing something.
Solution 3 means the client always needs to request for all data. This is nearly impossible to do because as you get more data, the time to retrieve and process them will make the app slow and unresponsive. It also doesn't make sense from technical and UX point of view.
Solution 4 also kinda defeats the purpose of using Core Data because it's the same workflow when we only store data in memory. You can still fetch and find objects but they might be invalid on the server already at the time of access.
Am I missing something? How is Core Data supposed to be used in this scenario? How do you ensure data consistency when the client doesn't have all the data? Thanks you in advance.

How to split an iOS sqlite db?

I have an existing iOS app that uses core data for app data and user data. My problem is that updating app data is a nightmare (my first app, so I didn't do it ideally the first time). I would like to split the app data and user data into 2 separate sqlite dbs (or stores, correct me if my terminology is wrong).
Any tips would be appreciated.
Having two sqlite files is a good idea. The pain is splitting them now.
Create a new store that only exists in your app bundle. Make sure the data is unchanged from when you first released the app.
You are going to need to walk the "user" store and find all of the data that is identical to what exists in the "reference" store and delete it. If the user has changed that data then I would leave it and let the user sort out duplicates.
Once that is complete your app can resume normal function and load up both stores. I would set a flag somewhere so that you know this has been done and you don't run the check on every launch. The "user" store's metadata is a good place.
Note, this will need to be done before the user can "use" your app. This probably means changing your launch routines so that if a migration and filter is needed you tell the user what is going on.
I don't think having multiple persistent stores is the right solution. You can simply have separate entities within a single persistent store. Core Data will handle it properly.

Resources