Core Data over using? - objective-c

I have an app that tracks a users driving trips (Paths). I save all the information using Core Data.
The db structure:
Path ->> Point
Point contains lat and long values.
What I do is, each time CLLocationManager is updated I add that point to an array. Once the user has reached the end of the path, I loop through and add all those locations to the db.
My question is...is this the best way to go about this? My two options are:
Add all locations to array, then add all locations to core data.
Each time CLLocationManager is updated, add that directly to core data.
I'm not sure if there is some best practice to accessing/altering core data. Should I do it in bulk (for loop), so that I can call
if ([managedObjectContext save:&error]) {
// handle save error
}
at the end of the for loop and keep it all condensed.
Or should I simply add a new Point each time CLLocationManager updates calling [managedObjectContext save:&error] after each update.
The only concern I have with Option1 is that if the app crashes while recording a path, none of the information will be saved.
So a benefit of using Option2 is that the data will be saved after each update but I'm not sure if accessing core data this frequent is bad practice.
Thank you very much for taking the time to help.

With the assumed frequency of NSLocationManager updates (max every few seconds) it is absolutely fine to save frequently. Also, your array will eat up more and more memory which is not really necessary.
You could still do it in discreet quantities, say, one save every 10 points.
Also you should perhaps save in applicationWillResignActive in case the app is interrupted.

Related

Use RESTKit for two way synchronization

is it possible to use RESTKit for two way synchronization?
I played aroud with RESTKit and CoreDate. Now I can download all data from my REST service and all changes (create/modify/delete objects) in CoreDate will be overwritten by RESTKit.
Now I want to choose between both versions (the local version or the remote version). How do I do this? Is there a way to manipulat the mapping, or something like that?
update:
My app should synchronize after some changes or after a specific delay (not difficult). Every object has a change date. Until now I want to keep the newer one (if they are equal the local one).
I hope RestKit is made for changing the strategy how it merges objects. something like a block I can set, where I get both objects and can return the merged object.
What I got so far:
I load the object via RestKit but do not persist them. Also I setup a CoreData store where I store the local objects. After loading the remote object I start to synchronize my self. First searching for pairs and then decide which to take, delete, create, overwrite, and so on...
But this is a big bunch of work and I think RestKit is doing something similar. Why not simply changing the strategy of RestKit for my requirements.
Well this would be the "syncing down" thing. After this I could write the synchronized data set back to the service. The changes are not very frequently so I will not have to check for new changes.
I hope now it's a little bit clearer
What you really want to do is validate the data coming in.
Since RestKit is using CoreData it automatically uses the validation built into CoreData (see here)
Here is an example that will ensure that the date never gets changed to an earlier one.
- (BOOL) validateChangeDate:(id *)ioValue error: (NSError **)outError {
if ([[*ioValue laterDate:self.changeDate] compare:self.changeDate] == NSOrderedSame)
*ioValue = self.changeDate;
return YES;
}
Note: There may be better/faster ways to test to see if we need to change the date
Note 2: According to the docs, if RestKit sees a value rejected, it fails the entire object, which we don't want, so that's why we always return YES and just change the incoming date
Note 3: We also don't want to change the value unless we have to because of what the CoreData docs say here
You may be able to leverage KVC validation to achieve this as it allows you to check and then edit or deny the change for each object and key. Check these docs.

managed object context take too long to load

I'm testing performance in my application, to see how it behaves with
a big load of data inside of it. My application is core data based and
uses array controllers in entity mode to fetch data.
What I discovered is that my app fetched all the managed objects
present in core data, so I set the fetch predicate of array
controllers at startup. This reduced dramatically the number of
objects fetched. The problem though is that my app still takes a lot
of time to start when is full of data.
I ran the app within instruments, and the core data fetches instrument
confirms that this is not the problem (my app fetches only 20-30
objects when starts). But running it under Shark I can see that for
4-5 seconds after startup the only call on the stack is to the app
managed object context. So I think it has something to do with
interaction between managed object context and data stored, even if I
don't fetch all the data. If I empty the app or leave little data
inside of it, it starts very quickly.
Does somebody know why this happens? Am I missing something obvious?
Why does it take so much to the managed object context to load if I
only fetch few objects? I always read that core data scales well and
the programming guide states that 10.000 objects are not much for core
data, but in my app it makes a big difference, so I'm wondering where
I am wrong.
amazing!
Just seconds after asking this questionI find the problem root and solve it !
Just for peoples who may face this problem :
you need to enable Use Lazy Fetching at the Object Controller for each NSArray Controller that you used in your application to solve the performance problem using core data managed object context
and here you go !
application starts as fast as you click on it !

Optimal data store memory usage?

I'm in the process of building a data store for keeping track of all the remote images being stored in my app. I've decided to use a singleton that will keep track of all the images being referenced.
As I remember, iOS automatically begins purging objects from memory based on recency of usage, whether or not it's being referenced by the current view controller, etc. However, if I store these images in a data store, those objects are always being referenced by the store itself. My solution for memory management was to keep track of when images were last called and keep some form of limit on the # and size of images being stored in the data store and purge the oldest based on age.
Is this solution a good one? Why or why not? Should I be depending on Apple's automatic memory management, or is having my own manager fine?
Further explanation:
Here's how requesting an image from one of my view controllers will end up looking with my solution:
[[HollerImages store]getImageWithUrl:#"https://www.google.com/logos/classicplus.png"
completionBlock:^(BOOL succeeded, UIImage *image){
if( succeeded ){
//Update the UIImageView with the returned image
}
}];
The store will then manage how many images are currently being referenced in the app and automatically de-reference old images as we hit some pre-defined limit. Thoughts?
Renaud Boisjoly (#rboisjoly) just sent me a link to this library which appears to provide the solution I was describing: https://github.com/rs/SDWebImage/
The easiest way to handle memory concerns is to just implement the -(void)didReceiveMemoryWarning function and clear out all your cached data there.
What you're talking about is implementing an expiring cache. You could just count the elements in your data structure at each insertion and remove elements from the head when you've hit the limit (provided it is an ordered data structure). The former solution is easier and works in most cases.

Is it good practice to work directly with core data whenever I need to manipulate my business objects?

For example. if I have a chat app that uses objects like: ChatRoom and ChatMessage. (both subclasses of NSManagedObject)
And throughout the app I need to: search chat rooms / add massages / create chat rooms and messages / and any other manipulate.
Is it ok if I do everything directly with core data? I mean every time I need to search a chat room or something like that, to do it with NSFetchRequest or NSFetchedResultsController.
You can access the data whenever you need, of course. On the other hand you should try to use caching mechanism as much as possible.
For example, if you are using your data in UITableView you should defintely go with NSFetchedResultsController as it was created explicitly for UITableViews. From the apple docs on NSFetchedResultsController:
It optionally monitors changes to objects in its associated managed object context, and reports changes in the results set to its delegate (see “The Controller’s Delegate”).
It optionally caches the results of its computation so that if the same data is subsequently re-displayed, the work does not have to be repeated (see “The Cache”).
Otherwise, if you need the data just temporarily, you can access them of course using NSFetchRequest each time they are needed or cache them in your business objects if they don't change or you know their lifetime otherwise.

Storing objects in iOS for later use

My app is pulling in JSON data from our web service. In all instances up til now, the information would be retained in memory or just refreshed on the fly with no need to retain anything locally other than the login token used in the API. With one of the new features we are adding, we will be taking in a group of locations, 26 max, with long, lat, radius, and name.
I also need to add 1-2 fields to this data to create a larger object. So my question is, what would be the best way to store this type of data in the iOS filesystem? Currently I have been using the NSUserDefaults, but that seems sort of limited or ill advised for larger amounts of data. Maybe not.
This data will need to be retrieved, changed or edited, and resaved. All of this while still retaining the ability to pull any of those 26 objects. Thank you in advance for reading and helping out.
For such a small amount of data (26 items) I suggest archiving.
Save to plist using NSKeyedArchiver/NSKeyedUnarchiver. Read your data from the delegate's didFinishLaunchingWithOptions, and listen for UIApplicationWillResignActiveNotification to save it.
A NSUserDefaults is a plist with features designed to store user preferences. It's often used instead a regular plist to save a couple of lines of code, which I think it's a bad idea because you get an additional complexity unrelated to your task.
If you want the login to be protected against someone stealing the device and performing forensics use the Keychain. You may want to use a wrapper and read some articles, comment if you are interested.
If you look for more features see Best way to store data on iphone but doesn't seem to be the case now.
Some code to get you started... Register to call save on app resign:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(saveMyData)
name:UIApplicationWillResignActiveNotification
object:nil];
On each object of the graph/dictionary/whatever you want to archive implement NSCoding:
- (void)encodeWithCoder:(NSCoder*)coder {
[coder encodeObject:myIvar forKey:kmyIvar];
}
- (id)initWithCoder:(NSCoder*)coder {
if((self = [super initWithCoder:coder])) {
self.myIvar = [[coder decodeObjectForKey:kmyIvar] retain];
}
return self;
}
Check out this guide on core data. It's the best way to store data locally on your device. It's a native cocoa API and it is bindings compatible. Plus, you can choose whether to store data as XML, SQLite, and Binary.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html
For anything remotely large, I would use this.
I had this same question and just figured out a much better solution.
What you could do is just store the JSON string as your NSUserDefault. Then, when you reload the app use the same method (or framework utility) you used to map the JSON string to your objects the first time. This way you can still take advantage of the ease of NSUserDefaults.
If you're using RestKit to manage your web services it gets even easier. The answer on this post shows how to use RestKit's JSON parser to map from JSON to your object.
Deserializing local NSString of JSON into objects via RestKit (no network download)