I am building an app that will require an offline mode when unable to get a wifi or data connection.
I am wondering what is the best solution for the following scenario.
Lets say my app allows users to view, add , amend an event on a calendar.
For the app to work off line i only need to store the current days worth of events. This could be be between 1 - 10 events. Each event will have a name, description and various other small properties.
I have been looking at coreData and am wondering if this maybe a bit overkill for what i need. I don't need to mirror the whole DB or anything like that.
Can I constructively use NSUserDefaults to store this king of information.
What are NSUserDefaults limitations in terms of what types you can store and how much.
The off line version will possibly need to store more entities than just the above so is it a viable method of storing data providing the amount of data is't massive.
Any advice would be great.
NSUserDefaults
NSUserDefaults is really meant for storing small pieces of data such as settings, preferences, and individual values.
NSUserDefaults offers a trivial learning curve and thread safe implementation.
CoreData
Learning curve may be a bit steep
CoreData and related classes provide easy ways to get your entities into UITableViews, like NSFetchedResultsController.
CoreData abstracts away a lot of the messy things you'd otherwise have to deal with yourself, such as lists of objects, one-to-many or many-to-many relationships, or constraints on object attributes, into a single nice clean object-oriented interface
CoreData manages save and undo functionality for you. It has a persistent store, which tracks changes, and can be flushed to the disk automatically at any number of times
However, if you're new to Cocoa I would avoid CoreData, to give yourself a chance to learn the basics first.
If I had to choose I would dive directly into CoreData. It makes sense also for small projects. NSUserDefaults is not meant to be used as a database (all the operations are ran on the main thread).
Coredata may be an overkill at first, but as your app grows so does your datamodel. CoreData is designed for such changes.
NSUserDefaults will store anything as long as the object complies to the NSCoding protocol, but its not meant to store a lot of information. Besides that, it can be difficult to fetch the data in NSUserDefaults, while it is rather easy in CoreData. Also note that relations between objects are unmanageable when storing objects in NSUserDefaults.
Related
I'm trying to write a iOS note taking app that is blazingly fast for a large number of notes and that syncs without ever blocking the UI. (Don't worry, it's just a learning project, I know there are a billion note apps for iOS). I have decided to use Core Data (mostly because of the excellent posts by Brent Simmons about Vesper). I know UIManagedDocument can do async reads and writes and has a lot of functionality built in, so I'm wondering if there is any information on which would be faster for a fairly simple notes app. I can't really find a lot of information about people using UIManagedDocuments for anything other than a centralized, basically singleton, persistent store. Is it suitable for 1000s of documents? Would it be faster or slower than just a database of NSManagedObjects? It seems like most information I can find about Core Data is oriented towards people using NSManagedObject, so any information about UIManagedDocuments being used in production apps would be really helpful. At this point, the only thing I can think of is to just write the whole app both ways, load 10,000 notes into it, and see what happens.
Update
To clarify, I'm not learning iOS development and Objective-C, the "learning project" mostly means that I've never used Core Data and would like to learn how to write a really performant Core Data application.
UIManagedDocument is designed/intended for document based applications. One UIManagedDocument instance per document. If you are not building a document based application then you should not be using UIManagedDocument.
Everything that people like about UIManagedDocument can be accomplished with very little effort using the Core Data stack directly. UIManagedDocument abstracts you away from what your persistence layer is doing. Something you really do not want.
If you want a high performance Core Data application you do not want to be using UIManagedDocument. You will run into issues with it. It will do things at random times and cause performance issues.
You are far, far, better off learning the framework properly.
In the case of Vesper, those are not documents; they are too small. Think of documents as Word files, or Excel files. Large complicated data structures that are 100% isolated from each other.
Also, whether you use a UIManagedDocument or not, you will be using NSManagedObject instances. NSManagedObject, NSManagedObjectContext, NSPersistentStoreCoordinator are all foundational objects in Core Data. UIManagedDocument is just an abstraction layer on top.
Finally, Core Data is not a database. Thinking of it that way will get you into a jam. Core Data is an object model that can persist to disk and one of the persistence formats happens to be SQLite.
Update (Running Into Problems)
UIManagedDocument is an abstraction on top of Core Data. To use UIManagedDocument you actually need to learn more about Core Data than if you just used the primary Core Data stack.
UIManagedDocument uses a parent/child context internally. Don't understand that yet? See the point above. What it also means is that your requests for it to save are "taken under advisement" as opposed to being saved right then and there. This can lead to unexpected results if you don't understand the point of it or don't want it to save when it feels like it.
UIManagedDocument uses asynchronous saves and at most you can request that it save. Doesn't mean it is going to save now, nor does it mean you can easily stop and wait for the save to complete. You need to trust that it will complete it. In addition, it may decide to save at an inopportune moment.
When you start looking for performance gains with Core Data you tend to want to build the stack in a very specific way to maximize the benefit to your application. That is application dependent and with the abstracts in UIManagedDocument you get limited very quickly.
Even in a situation where I was building a document based application I would still not use UIManagedDocument. Just to much behind the curtain.
Performance is likely to come down to how the rest of your code is implemented, and not necessarily the difference between a UIManagedDocument or a NSManagedObject.
Think of UIManagedDocument as a specific niche implementation of CoreData, that already has the parts of CoreData you want baked into it's structure to save you (the developer) a little bit of time writing code. It's been purpose built for handling UIDocuments, and multi-threading.
Under the hood, it's likely that UIManagedDocument is using CoreData as well as you would (assuming you know what you're doing), but it's theoretically possible you could cut some corners by knowing the exact and inane details of your implementation.
If you're new to CoreData, or GCD and NSOperationQueue, then you'll likely save a ton of developer time by leveraging UIManagedDocument instead of rolling your own.
A very apt analogy would be to using a NSFetchedResultsController to run your UITableView, rather then rolling your own CoreData and UITableView implementation.
If you're new to objective-C, I'd recommend you bang out something functional with UIManagedDocument at first. Later you get lost in the weeds of dispatch_asynch() and NSFetchRequest, and pick up a few milliseconds of performance here and there.
Cheers!
Just store a plain text file on the disk for each note.
Keep a separate database (using sqlite or perhaps just -[NSDictionary writeToFile:atomically]) to store metadata, such as the last user modification date and the last server sync date for each note.
Periodically talk to the server, asking it for a list of stuff that has changed since the last time you did a sync, and sending any data on your end that has changed in the same time period.
This should be perfectly fast as long as you have less than a million note files. Do all network and filesystem operations on an NSOperationQueue.
I'm developing an iOS application using Core Data. I want to have the persistent store located in a shared location, such as a network drive, so that multiple users can work on the data (at different times i.e. concurrency is not part of the question).
But I also want to offer the ability to work on the data "offline", i.e. by keeping a local persistent store on the iPad. So far, I read that I could do this to some degree by using the persistent store coordinator's migration function, but this seems to imply the old store is then invalidated. Furthermore, I don't necessarily want to move the complete store "offline", but just a part of it: going with the simple "company department" example that Apple offers, I want users to be able to check out one department, along with all the employees associated with that department (and all the attributes associated with each employee). Then, the users can work on the department data locally on their iPad and, some time later, synchronize those changes back to the server's persistent store.
So, what I need is to copy a core data object from one store to another, along with all objects referenced through relationships. And this copy process needs to also ensure that if an object already exists in the target persistent store, that it's overwritten rather than a new object added to the store (I am already giving each object a UID for another reason, so I might be able to re-use the UID).
From all I've seen so far, it looks like there is no simple way to synchronize or copy Core Data persistent stores, is that a fair assessment?
So would I really need to write a piece of code that does the following:
retrieve object "A" through a MOC
retrieve all objects, across all entities, that have a relationship to object "A"
instantiate a new MOC for the target persistent store
for each object retrieved, check the target store if the object exists
if the object exists, overwrite it with the attributes from the object retrieved in steps 1 & 2
if the object doesn't exist, create it and set all attributes as per object retrieved in steps 1 & 2
While it's not the most complicated thing in the world to do, I would've still thought that this requirement for "online / offline editing" is common enough for some standard functionality be available for synchronizing parts of persistent stores?
Your point of views greatly appreciated,
thanks,
da_h-man
I was just half-kidding with the comment above. You really are describing a pretty hard problem - it's very difficult to nail this sort of synchronization, and there's seldom, in any development environment, going to be a turn-key solution that will "just work". I think your pseudo-code description above is a pretty accurate description of what you'll need to do. Although some of the work of traversing the relationships and checking for existing objects can be generalized, you're talking about some potentially complicated exception handling situations - for example, if updating an object, and only 1 out 5 related objects is somehow out of date, do you throw away the update or apply part of it? You say "concurrency" is not a part of the question, but if multiple users can "check out" objects at the same time, unless you plan to have a locking mechanism on those, you would start having conflicts when trying to make updates.
Something to check into are the new features in Core Data for leveraging iCloud - I doubt that's going to help with your problem, but it's generally related.
Since you want to be out on the network with your data, another thing to consider is whether Core Data is the right fit to your problem in general. Since Core Data is very much a technology designed to support the UI and MVC pattern in general, if your data needs are not especially bound to the UI, you might consider another type of DB solution.
If you are in fact leveraging Core Data in significant ways beyond just modeling, in terms of driving your UI, and you want to stick with it, I think you are correct in your analysis: you're going to have to roll your own solution. I think it will be a non-trivial thing to build and test.
An option to consider is CouchDB and an iOS implementation called TouchDB. It would mean adopting more of a document-oriented (JSON) approach to your problem, which may in fact be suitable, based on what you've described.
From what I've seen so far, I reckon the best approach is RestKit. It offers a Core Data wrapper that uses JSON to move data between remote and local stores. I haven't fully tried it yet, but from what the documentation reads, it sounds quite powerful and ideally suited for my needs.
You definetly should check these things:
Parse.com - cloud based data store
PFIncrementalStore https://github.com/sbonami/PFIncrementalStore - subclass of NSIncrementalStore which allows your Persistent Store Coordinator to store data both locally and remotely (on Parse Cloud) at the same time
All this stuff are well-documented. Also Parse.com is going to release iOS local datastore SDK http://blog.parse.com/2014/04/30/take-your-app-offline-with-parse-local-datastore/ wich is going to help keep your data synced.
I've developed quite a few local apps, however this is the first time I'm introducing networking (more specifically posting to, and reading from a database). I am receiving back a JSON object from the database but I am currently using arrays and dictionaries. The objects do have relationships to each other, and I was wondering whether CoreData is the way to go. If so, do I just replicate part of the database I wish to be made viewable in the app and store it in my CoreData model? Are there any tutorials out there for this?
Also, just as a side note, I've also included Facebook integration with which I download the users list of friends. Would CoreData be good for storing this kind of information too? Or would I be better sticking with dictionaries?
Thanks in advance.
Based on my experience (other could say different things) Core Data is the right choice but its adoption could depend on the time you could dedicate to it. At first could be very complicated but I think you could take advantage applying the knowledge in some other projects.
Out of there there are some tutorials or books on Core Data.
First I suggest to read about core-data-on-ios-5-tutorial-getting-started. In the site there are, I think, other tutorials. Then, you could try to read a post on core data I've written some time ago: Mapping Business Objects with Core Data in iOS. Also Apple doc is your friend. So read the Introduction to Core Data Programming Guide to have the details that are going on.
If so, do I just replicate part of the database I wish to be made
viewable in the app and store it in my CoreData model?
Yes, just a part. You can create a minimal model that includes the key parts you need to have in your device. What I want to highlight is that you don't need to take care of normalization concepts when you deal with Core Data. Yes you could, but in CD you deal with objects and it's important to make attention to memory consumption (the framework helps you) and performances.
Would CoreData be good for storing this kind of information too? Or
would I be better sticking with dictionaries?
With CD you could take advantage of NSFetchedResultsController. A NSFetchedResultsController objects is optimized to work with tables and it used to display data also in batches. Through this component you can deal with a lot of elements (say friends in Facebook) without overload the memory. See core-data-tutorial-how-to-use-nsfetchedresultscontroller.
If you want to know something else, let me know.
Hope that helps.
I am developing an app which consists of a UINavigationController and UITableViews, there will be many items (50+) at the root view of the nav controller and maybe 30 rows in each of the detail views.
What is the most efficient way to populate the lists? Core Data or Plists?
There is scope within the specification to push updates to the lists on a monthly basis, so they always stay current. Would this affect the choice, which method is easier to bulk update?
Thanks
I would choose Core Data.
It is relatively easy to use; and it gives you more flexibility if the app needs to grow. Core Data can be backed by SQLLite, and thus can be quite performant. Also bulk updates is manageable.
Core Data is by far the best, especially since you want to be able to make updates to this data later on
Regarding updates. I wouldn't 'push' these out but rather have the app poll for them, perhaps on launch, then fetch anything new in the background.
Edit: Also with Core Data and using a NSFetchedResultsController it is very easy to smoothly animate in new records into a UITableView as they are added in the background to the data store
Imho, I would try to keep things simple, following the good old KISS principle.
In your current case, it seems that you just need to display read-only data, so all you need is the data (say a file, in plist format, or xml, or json, or csv, or whatever. just parse the file, populate your business objects, add them to an array. Use that array for your master and detail view. No need for core data here (asumming by 50+ you don't mean 50 - 50'000, because in that case, core data's memory management would help ;-)
If in the future you need to handle updates, you will either update the whole list, thus in fact just replace the old file (simple), or do incremental changes. I would only recommend to consider to start using core data in the latter case.
I'm personally using core data in a couple of projects, and I love it. But I wouldn't recommend it just because it's there, after all it brings overhead and complexity. If you want to use core data, you'll need to invest some time to understand it's concepts. Don't underestimate that, there's a lot of stuff to read and understand, and probably a couple of WTF moments (just look for core data questions here in SO).
Just to be clear: I don't want to talk you out of using core data, I'm just asking as your mother probably would: do you really need it?
I have read tutorials and found different methods for saving your data such as pure SQL, Core Data, Archives and NSUserDefaults.
I am thinking about creating an Application that will be kind of an RPG where I will create a class with different variables.
This class and it state must be saved an persist through App cancellation, iPhone booting and App updating.
I. Which ones of the previous methods fullfill this?
Also I have a Q about Core Data.
If I just want to store a variable, lets say a date for instance, in an entity. Lets say that the property is called dateJustNow and it is an attribute.
II. Do I have to create new rows for each saving of dateJustNow? Or are there other ways to save only ONE state of an variable and fetch it when needed?
Maybe I am mixing variables (singles) and attributes (collections)?
Sincerely yours
The rule is:
Use NSUserDefaults to save application state information. This is information about the operation of the app itself e.g. last launch time, preferred font, last open view etc. The user defaults are universally accessible and fast but lightweight. They can store only bits and pieces of data and they don't store any logic.
Use Core Data to model, manage and persist the actual data and logic that the app deals with. Core Data manages large, complex data and its associated logic.
In the case of game, you would use NSUserDefaults to save data about the operation of the app e.g. the user can set a preference for which view the app will startup to. However, the actual logic and data that encodes the rules of the game and changes in the game state should go into Core Data.
To me, it sounds like you are looking for an OR-mapper. Use SQLite directly to save states. If you were to write a multi-player online RPG, Core Data would have been great for the large amounts of data.
From this answer:
Although Core Data is a descendant of Apple's Enterprise Object
Framework, an object-relational mapper (ORM) that was/is tightly tied
to a relational backend, Core Data is not an ORM. It is, in fact, an
object graph management framework.
Also, here's a very good read: http://inessential.com/2010/02/26/on_switching_away_from_core_data