I want to get friends information from Facebook and save it with Core Data.
I build a FriendsManager Class that gets the a list of friends from Facebook (name and id)
and a FriendInfo Class that takes the id and gets all the info about this friend.
I thought I'd do it this way:
Create an object of FriendsManager let it get all my friends (not really a problem);
in the FriendsManager create an instance of FriendInfo;
give it the id and let it get all the info I need including geocoding of hometown;
save all this with core data.
But then where do I release this object?
In Order to get all the friends info I would create these objects in an loop that goes through my Array with friend ID's.
I also do all the getting info & geocoding with Grand Central Dispatch so do not really know when a FriendInfo got all the data it needs and is ready.
A Core Data object is usually a subclass of NSManagedObject, not a NSObject. You don't alloc or release it, you create one with the ManagedObjectContext and you either save or delete it but you don't release it because you don't own it.
A NSObject (prior to ARC) follows the usual rules of memory management - simply, if you get it through alloc, copy or a method starting with new, it is yours and you need to use release when you no longer use it. If you get it without allocating it - for example "NSString *string = [NSSTring stringWithFormat:#"test"]; then it is autoreleased and you don't need to release it.
Trust the analyser - shift-command-B.
Sounds like you might want to define your core data model and then create a NSManagedObject subclass for the friends information. You would create it using something like [NSEntityDescription insertNewObjectForEntityForName:#"FriendInfo" inManagedObjectContext:moc]; rather than [[FriendInfo alloc] init] as you would if it were a NSObject. The shift in thinking is that the object is created and managed by the ManagedObjectContext before you put any data in there, you request a new one and put in the data, then inform the ManagedObjectContext what you want done with that object - save or rollback (reverse all changes since the last save).
The problem you explain is rather "high-level" and it is difficult to give concrete advice. But in general you might want to just use ARC and don't hassle with most of these memory management problems you mentioned.
Also since you mentioned that you want to use core data, you would not release any of the objects you want to save since core data saves all objects of the context and so they never get "freed" anyway.
Your suggested approach about using a GeneralManagerClass to retrieve all the info and fill new instances of friends is generally OK. I also do it this way and it makes thinks relatively easy.
So I would just start with it and then ask more concrete questions. For now, I really don't see any general difficulty in the issues you mentioned if you follow the route you suggested...
Related
I'm building an app which receives a number of listings from a web API, and allows the user to save some for offline viewing. My usual approach would be:
Get the data from the API, and make a new Listing object for each datum
Save the object to the DB if the user chooses to do so.
But this is a Core Data app, so the context is what gets saved, not the object. Under those circumstances, the above would become something like this:
Get the data from the API, and make an unmanaged Listing object for each datum
Move the object into the managed context if the user chooses to do so, then save the context
One approach to having an unmanaged and a managed version of Listing objects would be to have two classes, e.g. ManagedListing and UnmanagedListing - but that's a horribly repetitive way of doing it.
What I'd like is to make Listing a subclass of NSManagedObject; initialise a bunch of them without an NSManagedObjectContext; then when I want to save one, I either set its context or I copy its attributes to a new Listing inside a context.
Can I make instances of an NSManagedObject in no particular NSManagedObjectContext? If so, how?
Use two persistent stores, one in memory and one on disk. If the user wants to save, move the object to the other store using assignObject:toPersistentStore:.
In iOS < 5.0 - yes.
In iOS >= 5.0 - no.
The question is quite simple: when should I use the save:(NSError **)error method of NSManagedObjectContext? From what I understand the only thing it does it save changed data to the persistent store. The Xcode template-generated application delegate calls the save: method on applicationWillTerminate, is that sufficient?
Details about my code:
Multi-threaded (doing operations in the background, thus using multiple NSManagedObjectContext's)
I'm using a single NSPersistentStoreCoordinator
Data changed on background threads is merged using mergeChangesFromContextDidSaveNotification:
If you need to know more, please do ask!
I couldn't find a guideline on when to call it, so I decided to ask you all. Thanks in advance for your replies!
You always need to call save: when you want your data to save. You can't always guarantee that applicationWillTerminate will be called. For example, if your application crashes due to memory issues (or due to one of a handful of other things) then this won't be called.
I would save data when the user completes the action that is actually generating the data to save.
I'm trying to make my first application using Objective C + Core Data, but I'm not sure it's the correct way, as it feels really weird to me.
I have only one data context, which I create at launch time, in the Application Delegate. This data context is used for all the operations (read, write). In another environment (C# and LINQ for example), I try to make these operations as unitary as possible. Here it seems I just have to create the data context once, and work with it without closing it ever (except when the application exits).
I also have an asynchronous operation in which I update this data. Of course, it uses the same data context again. It works, but doesn't feel right.
My Application Delegate keeps a NSArray of the objects contained in Core Data. I use this same NSArray in all my views.
I would actually naturally close the data context once I got all the objects I require, but... aren't the objects always attached to the data context? If I close or release the data context, all these objects will get releases as well, right?
As you can notice, there is something I'm missing here :) Thanks for your help.
The NSManagedObjectContext to which you refer is more of a "scratchpad" than a database connection. Objects are created, amended, destroyed in this working area, and only persisted ("written to the database" if you prefer) when you tell the MOC to save state. You can (and should) init and release MOCs if you are working in separate threads, but the App Delegate makes a MOC available so that all code executing on the main thread can use the same context. This is both convenient, and saves you from having to ensure that multiple MOCs are kept in sync with each other.
By keeping an NSArray of Core Data objects, you are in effect duplicating its functionality. Is there any reason for not working with an NSSet of Core Data objects provided by the MOC?
If you are working asynchronously, then you should not be sharing an NSManagedObjectContext object across threads, as they are not thread-safe. Instead, create one for each thread, but set them to use same NSPersistentStoreCoordinator. This will serialise their access to the persisted data, but you'll need to use notifications to make them each aware of the others changes.
There is a good tutorial/description on how to use Core Data on multiple threads here:
http://www.duckrowing.com/2010/03/11/using-core-data-on-multiple-threads/
1) CORE DATA AND THREADS, WITHOUT THE HEADACHE
http://www.cimgf.com/2011/05/04/core-data-and-threads-without-the-headache/
2) Concurrency with Core Data
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdConcurrency.html
3) Multi-Context CoreData
http://www.cocoanetics.com/2012/07/multi-context-coredata/
I was wondering what your thoughts were on persisting objects (NSDictionarys and NSMutableArrays of Objects) on the iPhone?
I've gone through a couple of options in my head:
1.) We persist using NSUserDefaults, this method seems the easiest and I sort of want to just go ahead and use this. The Data I want to store would only maybe be a few kilobytes of objects.
2.) Using NSKeyedArchiver (the exact name alludes me atm) to archive/serialize and then just puting that into a SQLITe database. but the problem with that is:
I need the data, when it's changed on the phone, to automatically be saved. NSUserDefaults has a synchronization method for this, but for method #2 I'd have to re-archive the entire array of objects, and then store it back into the database. This seems like a lot of work.
3.) forgot about this I've heard things about CoreData being able to handle this sort of thing, but I'm not sure if I understand exactly.
So what do you guys think? Do you have any other suggestions?
I recommend going the extra mile and use Core Data.
First you will learn a new thing, a good thing.
But further more your app will start up faster and handle data much more fluently as data is fetched in chunks rather requiring reading the whole dataset.
...don't be afraid, just try it. Start small and keep going.
I think NSDictionary and NSArray has writeToFile:atomically: instance methods that serializes and writes them to your given filename. You could add the observer for your NSDictionary or NSArray which writes them after they get changed.
I've used both NSKeyedArchiver and writeToFile:atomically: on a few of my own apps with great success.
Performance has been great. You can repeatedly persist a few thousand lines of text and not notice.
Personally, I avoid sqlite unless you need querying. You'd be surprised what you can get away with using only NSDictionary filled with NSArray
The advantage to using NSKeyedArchiver is once you start creating "Domain Objects", you can persist those the same way. For this reason, I use NSKeyedArchiver 99% of the time.
I'm working on a Core Data iPhone app that pulls remote resources from the web into NSManagedObjects and saves them locally.
I want the user to be able to designate which of these objects should be saved. This means that some will be saved, but many should be deleted. However, I might want to save and delete at different times - I'd prefer to save designated objects immediately (in case the app crashes), but still keep around the other objects because they're hanging out in table views and such.
One approach I can think of is to have a different persistent store - one for stuff that will be saved, one for stuff that won't; this way I can save the "should be saved" store at any time. However, I would much prefer to keep objects of the same type in the same domain.
Another approach would be to just save at the very end - negating any ability to recover from a crash. But saving at the end would allow me to parse out any objects that weren't designated "should save".
And that's really what I want - a "shouldSave" method in the NSManagedObject class, or at least a save method that I could fire at select objects. But as far as I can tell, neither of those exist.
So, if anyone has any other suggestions, please let me know! It would be greatly appreciated.
CoreData is not for object serialization, it is an object graph serialization. That is an important distinction. Once you have an NSManagedObject it is associated with a context, and CoreData handles saves at context level since that is the only way it guarantee any sort of object graph consistency. In other words, you can't save individual objects because if they have relationships with other objects you would need to also save those objects and it quickly cascades out to the whole graph.
You seem to be worried about crash recovery. If the app crashed and the user relaunched it would they expect to see just the items they saved, or everything that was on the screen before they crashed? If it is the former you should just delete them at save time and remove them from the users view (with some animation), if it is the later you should commit out everything, and potentially delete the objects you are not interested in at another time.