Problem: I'm implementing aplication where user is dowloading lots of objects in xml. To reduce peak memory footprint I want to parse data to Core Data and then use batching to display them in table view. I don't want them to be saved anyhow because objects will be changing everyday but I want to let user choose its favourites object and then save them. Favourites will be displayed in different table view.
Solutions I'm thinking about:
Create two NSManagedObjectContext (one main and one tmp). Parse objects to tmp, if its marked as favourite copy object to main and save it from there.
Forget about memory and keep data in some array and save only choosen ones.
Save all using one NSManagedObjectContext and before application will terminate delete unmarket as favourites.
Any hint here would be nice. Also some code sample code with solution one because I'm new to Core Data and I may have problems. I've been looking for suitable solution for two days now.
I would suggest you forget about optimizing the memory footprint unless/until you have some hard evidence showing that this will in fact be needed. But of course it depends on what "lots of objects in xml" means exactly.
I am assuming you are not downloading millions of XML documents just to throw them away again when the application finishes (because that would be a serious waste of network resources). In contrast, an array with a few hundred or even a few thousand small XML-like data structures would most likely be nothing to worry about as far as memory is concerned.
That being said, if you would need to save both temporary and persistent data with Core Data after all, I would go for a single NSManagedObjectContext with two entities rather than two separate contexts. Or you could even have a single entity and mark certain instances as temporary data. Managing two different contexts means additional overhead while I don't really see any advantages to that approach.
Related
Okay, I can't seem to find a clear answer to this question of storage on the iPhone. My model class has several ivars and two very large (MB) mutable arrays of data that are collected from an external device and then analyzed. What I'm thinking is that you have data in the object (similar to a note or a music file) and you can save it to a permanent data "file", and then later open old data "file" and view it (no editing of old data will be done). Along side this I want another stored object that keeps track of a few key bits of information from each of the data files, and also has references to them (maybe the user could click a data point, and it would open the corresponding data file - if it still exists (it could be deleted by the user to save space)).
I see tons of advice recommending all data storage for iPhone apps should use Core Data. The thing is, except for the one side "file", there are no relationships between objects. The objects could be thought of as notes or music files, they don't care about the existence of each other, and there is only one object in existence ("loaded") at a time (either in memory with data being added to it, and to be saved later, or loaded from storage being viewed).
What is the best way to manage this? Currently a device controller (handles the device communication) creates the model, and sends data to it (the model parses and analyzes the data). But should there be some controller that handles files (or Core Data managedobject, whatever) that creates the object, and the saves its data, releases its memory and then loads a new one with stored data?
Any advice would be helpful, as the best storage examples I've found seem to be very relational (employee,boss,company) - which I can see would benefit from a database. But at the same time, manually keeping a list of files in a directory may be more work than some other method.
I can't find citation in Apple's documentation but I have read (and been told by Apple engineers) that "large" data objects are sometimes best stored outside of Core Data. The model that has been suggested places BLOBs (Binary Large OBjects) in file system with Core Data objects referencing these large objects (i.e., storing relative or absolute file paths).
So, assuming that your BLOBs are music data, then you might have your Core Data model have an entity that holds meta-data (e.g., size, time/duration, etc.) as well as reference to file that holds actual data. Your meta-data entity could also have relationships with other entities within your system. For example, you might store spectrograms for music data and have those held by a separate entity.
I wrestled with this issue for data that was being sampled from various measurement sensors. Ultimately, I decided that my data sets were small enough (in most cases) to store with Core Data as NSData properties of dedicated entity. The wrapping entity was 'dedicated' so as to avoid loading data just to display meta-data to user.
Update
I found line about BLOBs in Core Data Programming Guide at the end of the "Large Data Objects (BLOBs)" section:
It is better, however, if you are able
to store BLOBs as resources on the
filesystem, and to maintain links
(such as URLs or paths) to those
resources. You can then load a BLOB as
and when necessary.
I'd also recommend using Core Data. While Core Data does make it easy to handle relations, no one is preventing you from using Core Data to store unrelated information. There is no rule against creating models in Core Data that have no relation with each other what so ever; just don't link them together.
Core Data will handle all the reading/writing to the database, which will save you the trouble of having to parse your own files. There is a bit of a learning curve when trying to use Core Data for the first time, but once you get it running, you'll be thankful it's there.
Unless you need any kind of database access (fast queries, frequent updates, etc.), a database involves too much overhead, in terms of both coding and performance. Database features are not exactly free, so I can think of a lot of scenarios where you will get better results with less effort if you go with one of the following:
multiple files with a separately stored index file;
a large file of your own binary format.
The choice depends on the number of items, the size of items, whether their sizes are identical, how often you need to modify the data and/or the index, etc.
I have 100s of file which needs to be accessed for displaying the content on iphone. They are all plists.
Which one is faster core data or file access ? which one is secured ?
You have to consider the file size first, a nice rule of thumb found in these boards is, if the file is under 100kB you can store it as an attribute in an entity as a BLOB, if it is greater that that you maybe want to create a ad-hoc entity for it, and in the end if it exceeds 1 MB in size you can access it through the filesystem.
Secondly, you shall evaluate the cost of the operation too, 100 files may appear many but if you access them few times, maybe file access is the way to go, on the other hand if you need that stored information multiple times frequently but you can even create ad hoc entities for Core Data and load the files at start up. And so on.
This is a nice book on Core Data. You can find many guide lines by reading it, but keep in mind also the general guide lines of designing databases.
If they are static files I would recommend pre-loading them into a Core Data SQLite file. That would yield far better performance, especially if you structure your model properly.
I have an app that currently holds all state in memory. It fetches a bunch of information from a server as JSON and then holds on to the JSON values in memory. Each JSONObject can be ~300 bytes and there can be thousands of such objects.
I use this data simply to populate UITableView.
In order to better handle large amounts of aata, I modified my code to fetch data from the server and store it using CoreData. There JSON objects can be represented as simple entities, each with 3 NSString attributes and one 1 int32 attribute. I created a NSFetchedResultsController to use as the data source of the UITableView. My assumption was that this would reduce the resident memory usage of my application (I assume NSFetchedResults controllers effectively manages memory to not hold entities that aren't being displayed in the view, vs holding all my state in-memory).
For the purposes of this discussion, let's assume my app purges the CoreData store and re-fetches all data each time it runs.
When I went to measure the changes in Resident Memory and Virtual Size using the VM Tracker in Instruments, I noticed that both these values remain almost identical. Infact, the Core-Data based version of my app seems to use more memory than when I have everything entirely in-memory.
While this may be true, I don't have an intuition for why this might be so. Any explanations?
From what I have said about my app, does it sound like I don't want to bother persisting in CoreData, and why?
Core Data can use more memory as you have seen, if there is memory to be had. However, one of the benefits to Core Data is when you get into a low memory situation. When that happens then Core Data will automatically reduce its own memory footprint as much as possible.
Another thing to consider is are you letting Core Data fault these objects? If you are pulling in 1000 objects and displaying 10 of them, then the other 990 should be in a faulted state and therefore taking up less memory.
I would run through the Core Data instruments and make sure you are not fulling realizing all of these objects by accident and unintentionally causing your memory usage to be higher than it needs to be.
Update
Sounds like you are importing this data and then not flushing Core Data properly if you are not seeing any faulting going on.
Assuming you are loading this data on first launch (which I would not do btw, I would pre-load the app and avoid the plist files entirely), you want to call -reset on your NSManagedObjectContext after the load is complete so that any objects that are not being used are flushed out of memory. Then as the data is coming back into memory (on use) it will be properly faulted.
Lastly, make sure you are using a SQLite store. Otherwise this is all moot.
Is Core Data still a good option to use for the iOS even if they data will only be quite temporary. i.e – data being sent up to a server in the cloud once within range of a network, and then never needed again on the mobile device.
You don't have to use Core Data to persist data.
If you don't want to persist the data at all, you can define an in-memory store which never writes to disk.
Core Data's true function is the management of an object graph i.e. it handles the relationships between objects. It's real advantage is the ability to automatically handle complexity.
That complexity can arise from the data objects themselves or from their needed relationships to controller or view objects. Either way, Core Data makes it easy to tie all the objects together without great gobs of custom code. Where the objects end up being persisted or even persisted at all, is really secondary.
Yes, if there could ever be a large number of records (e.g. user is overseas, doesn't have a data connection), use Core Data. The point of the Core Data abstraction is just this - if you only have 10 records max, ever, it may just use a flat file of data, or maybe a Sqlite database if more than that -- by "handing the problem" over to Core Data, you make storage decisions Apple's problem, and for free you'll get all the optimizations that Apple'll throw into the Core Data framework in the coming years.
Core Data is complex when you first look at it. Apple's API docs aren't bad, but there are a few "gotchas". If you've worked with anything like the Entity ORM framework, etc, it's really easy to pick up.
Alternatively, if you're reasonably certain that you're only going to get 5-10 records, and the data is anything that conforms to NSCoder, you could just archive it and save it, and then unarchive it when you launch the app. Also, if it's array data, a plist is pretty nice.
The approach I take is to insert entities into a NIL context and provide a base class for insertion into a valid context when I wish to persist them. Code can be found here... Temporary Core Data
My plan is to display a list of items alphabetically in a table view that has about 100 items. Each item has an image, a list of times and a description that the tableview will drill down to. What I am struggling with is the correct way to store and load this data. Some have told me that a plist will be too data heavy and that core data is too new. Should I just create arrays?
You're not clear about what you intend to do with this data. Plists and Core Data are both persistence formats (on disk). Arrays are an in-memory format (and can also be slapped onto disk, I suppose, if that's what you want to do, but inventing your own binary disk format is only something you should consider very rarely, and certainly not in the case you probably have).
In memory, you can probably just use an array (NSArray) and have each element perhaps be an NSDictionary of the other properties relative to that entry. That sounds like the model of your MVC design, which you can then hook up to the table view.
As far as persisting this to disk, it depends on whether 100 items is a fixed amount, a ballpark, or a minimum, etc. Plists (see NSKeyedArchiver) are great for all the data except possibly the raw image data-- you might want to keep those "to the side" as separate image files with filenames in the plist.
I don't know much about Core Data, but it's not that new, and it's not untested, so if it does what you want without much hassle, go for it.
Serialize it into an Archive using NSCoding Protocol. See Guide.
I'd use an NSArray of business objects implementing NSCoding and then just archive them.
I usually default to Core Data unless I have a compelling reason not to. (Of course, I have learned Core Data so that makes it easy for me to this.)
Core Data has the following advantages:
It has an editor in which you can create complex object graphs easily
It can generate custom classes for you data model objects.
The generated classes are easily modified.
Core Data manages the complexity of adding, deleting and saving objects.
Core Data makes persisting an object graph almost invisible.
NSFetchedResultsController is custom designed to provide data for tables.
100 objects is a small graph that Core Data can handle easily. It's a lot easier to use Core Data than it is to write custom coders to archive custom objects. For exmaple, at present, I have an app with over a dozen major entities each with two or three relationships to other entities. Hand coding all that would be a nightmare.
Core Data has something of a steep learning curve especially if you've never worked with object graphs before but if you're planning on writing a lot of Apple platform software, learning it is well worth the time.