My app has it's own sql database with let's say 2000 rows.
I know that in future I will add some new and delete some old. Each row got prioritet parameter that changes in order of user interaction.
I want to store all prioritets locally so my future app updates would not erase them.
So the question is what is the best way of doing that? Remember that I will need fast access to those prioritets in future and they must be easily mutable.
Related
I'm in the middle of adding an "offline mode" feature to an app I'm currently working on. Basically the idea is that users should able to make changes to the data, for example, edit the description of an item, without being connected to the internet, and the changes should survive between app launches.
Each change would normally result in an API request when working online but situation is different in offline mode.
Right now this is implemented by storing all data coming from the API in a Core Data database that acts as a cache. Entities that can be edited by user in addition to normal attributes have the following ones:
locallyCreated - whether the object was created offline
locallyDeleted - object was deleted offline
locallyUpdated - updated
This makes it possible to look for new/deleted/updated objects and send corresponding API requests when doing sync.
This worked well for creating and deleting objects, however, one disadvantage I found with this approach is when new data is retrieved from the API all local changes (i.e. attributes of objects marked as locally updated) are lost, which means that they have to be stored separately somehow.
What would be the best way to approach this problem?
Since you have your locallyUpdated key, the obvious answer is to modify your code that imports server changes, so that it doesn't overwrite changes to any object marked as changed. One way or another you need to avoid overwriting those changes, and you're already keeping a record of which objects have changes, so you already have the tools for a basic solution.
But you'll soon run into the complexity of syncing data. What if the local object has changes on one key, but the incoming data from the server has changes on a different key? You can't resolve that just by knowing that the local copy has changed somehow. Maybe you decide that the server always wins, or that the local copy always wins. Those are easy, if they make sense for your app. If you need to merge changes though, you have some work ahead of you. You would need to record not only a Boolean value indicating that changes were made, but also a list of which keys had changed. This can get complicated, but it's the nature of data syncing.
I have a requirement in which locally created events have to be synced with sever synchroniously. To explain this briefly lets consider this scenario, there were two events occurred in the offline app called A and B here A > B. In this case B should sync only when A is completed its sync.
To fix this I must have an extra attribute in my entity to identify which is created earlier. This attribute can maintain either created time or any incremental number.
Here only i am facing some clarifications
Solution :1 Based on created time
If I maintain created time in that attribute, Will it be proper for below scenario
Lets say I created on event “A” today then I changed my device’s date to previous day’s date and then I am coming back to my app and creating an another event “B”. Here which one will be earlier? if app says “B” is most recently inserted object then there is no issue I can stick with this solution itself otherwise I need to move to some other solution. Is there any optimised solution to find inserted order by maintaining created time?
Solution :2 Based on incremental number
I believe core data does not provide any auto-incremental id so we need to maintain it manually. If so what would be the better approach to maintain the maximum assigned value? Will it be good if I store the maximum assigned value in NSUserDefaults? Whenever app creates an event the value will be fetched from NSUserDefaults and +1 will be added and then I will assign final value to the event. Is this approach proper one? or else please guide me if you know any better solution
There is no auto-incrementing number built into Core Data as that is more a business logic specific item. However, it is not difficult to implement.
You can store the last number used in the metadata of the persistent store. During your insert, simply increment that number, add it to each entity as you go. When you are done inserting, update the number in the metadata.
That is how Core Data updates its own insert numbers for the objectID.
I have to ship a simple app with a very tight deadline so I have no time to learn anything othen than what I know (meaning learning Core Data for example). Would it fine to use NSUserDefaults to store data for my app? It's almost like a check list app where users have list of items with some data accompanying each item.
Other than that I would be using a service like Parse which I can handle thanks to having built my last app with it.
Would Apple reject an app if you use NSUserDefaults for something other than settings/preferences?
Thanks!
From Apple's documentation:
The NSUserDefaults class provides a programmatic interface for interacting with the defaults system. The defaults system allows an application to customize its behavior to match a user’s preferences. For example, you can allow users to determine what units of measurement your application displays or how often documents are automatically saved. Applications record such preferences by assigning values to a set of parameters in a user’s defaults database. The parameters are referred to as defaults since they’re commonly used to determine an application’s default state at startup or the way it acts by default.
[...]
Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value. For example, if you set a mutable string as the value for "MyStringDefault", the string you later retrieve using stringForKey: will be immutable.
In other words, this is not the place to store mutable application data.
If the checklist data is going to be modified by end users (i.e. adding new items, or editing the text of the items on the checklist) it really would be worthwhile to learn how to use Core Data. Over the years it really has become very easy to learn and use.
You can find a great series of Core Data tutorials at http://code.tutsplus.com/series/core-data-from-scratch--cms-653
If you're looking for something that's been updated for iOS 8 and Swift (although they're mainly syntax changes for the new language), you can check out http://www.raywenderlich.com/85578/first-core-data-app-using-swift.
Apple wouldn't reject even if you unnecessarily burden NSUserDefault. But users of your App will definitely uninstall it or OS will kill it if app crashes or hangs their iPhone.
NSUserDefault : is a fast way to access the data. it stores in (key,value) pair and lives as long as your app is installed in phone. Usually session based small amount of data is supposed to be stored in it. Not ur entire database.
Database (CoreData or Sqlite) : Behind the seen Coredata is also a sqlite with objects talking to each other(Think in terms of model instead of tables if using Coredata).
I simple suggest you use Coredata if your data by any chance is big or expected to get big. CoreData wont take much time.
Yes, you can store data in NSUserDefaults, which will be the quick and dirty method to store data locally.
You could use Core Data, though I prefer to just use FMDB and write my own SQLite statements. You could also use NSFileManager and just read and write everything to a JSON file. Parse will probably be overkill if all you are doing is storing a list of check list objects.
Go for NSUserDefault fro now !
When the App is submitted fro approval, look at SQlLite. this will be useful for the next projects.
Parse... sure but make sure it's not overkilling especially if you have limited amount of data
Good Luck !
The question is merely theoreticaly, really a rare use case, I'm just wondering about.
I have a client-server setup (CoreData, JSON, AFNetworking, etc.) where every account have multiply read-write users.
Therefore I timestamp every database entry with a _lastModificationDate to be able to sync / merge changes later.
So one of the users go offline, sets it's date to 2030 (with Set Automatically off). Save - so timestamp with 2030 - some entity, then go online.
20 years passed, user did not change a single thing. Still, every sync of this user will overwrite data in database until we pass 2030.
How should I get over this?
You could either set a new field modifiedOffline (boolean), or, while he's offline, set _lastModificationDate +1 on each modification. However, in both situations, the updates from the server will/may overwrite the local ones, even if they're newer.
Another solution would be: after the user gets online, the app would refresh the _lastModificationDate to be at maximum current date (which I presume you fetch it from the server). This way, newer modifications will work normally.
The server database could have a sanity check. Modification dates in the future get set to the current date when first encountered. Maybe also dates pre-dating the iPhone ;-).
I have what I would presume is a very common situation, but as I'm new to iOS programming, I'm not sure of the optimal way to code it.
Synopsis:
I have data on a server which can be retrieved by the iPhone app via a REST service. On the server side, the data is objects with a foreign key (an integer id number).
I'm storing the data retrieved via REST in Core Data. The managed objects have an "objId" attribute so that I can uniquely identify the managed objects in the rest of my code.
My app must always reflect the server data.
On subsequent requests made to the server:
some objects may not be returned, they have been deleted on the server - in which case I need to delete the corresponding objects from Core Data - so that I'm reflecting the state of the server correctly.
some objects have attributes which have changed, therefore the corresponding managed objects need updating with the new data.
my solution - and question to you
To get things going in my app, I made the easiest solution of deleting all objects in Core Data, then adding all new objects in, created with the latest server side data.
I don't think this is the best way to approach it :) As I progress on with my app, I now want to link up my tableview with NSFetchedResultsController, and have realised that my approach of deleting everything and re-adding is not going to work any more.
What is the tried and trusted way of syncing Core Data with server side data?
Do I need to make a fetch request for each object id I get back from the server, and then update the object with the new data?
And then go through all of the objects in core data and see which ones have not been updated, and delete those?
Is that the best way to do it? It just seems a little expensive to do a fetch for each object in Core Data, that's all.
Pseudo code is fine for any answers :)
thanks in advance!
Well, consider your download. First, you should be doing this in a background thread (if not, there are lots of SO posts that talk about how to do that).
I would suggest that you implement what makes sense first, and then, after you can get valid performance data from running Instruments, consider performance optimization. Of course, use some common sense on "easy" performance stuff (your design can take care of the big ones easily enough).
Anyway, get your data from the online resource, and then, for each object fetched, use the "unique object id" to fetch the object from core data. You know there is only one object with that ID, so you can set fetchLimit to 1 on your fetch request. You can also configure your "object id" attribute to be an INDEX in the database. This way, you get the fastest search from the underlying database, and it knows to stop looking once it finds your one object. This should be pretty snappy.
Now you have your object. Change any attributes necessary. Save, rinse, and repeat.
Furthermore, for several reasons, you may want to know when objects were last updated. I'd suggest adding a timestamp to each object that gets changed with the current time every time an object is changed. This will also help in deleting objects. Since your online database does not tell you which objects are deleted, you must have some way to know that an item is "old and no longer needed."
An easy way to do this is to remember the time you started your update. After processing all objects from the download, you now have a way to find all the objects that were deleted from the online database. Basically, any object with a "last update" timestamp before the time you began the update should be removed (since they were not added or modified in the last update). You can also index the database on this field, which will make finding those objects faster - unless your database is huge, I'd wait to see what Instruments has to say about this one though.