Creating instance for NSManagedObject Class using Restkit - iphone

how can i create an instance for NSmanagedObject Class which i am created using core data model. I have another class which is the subclass of NSObject. I want to create an object for NSManageObject Class. how can i do that. Is it like the normal way that we create the instance for NSobject class like
ClassB.m //ClassB is NSObject Class
ClassA *obj = [[ClassA alloc]init]; //ClassA is NSmanagedObject Class
or is there any way to do that???
i am not using this code(Apple Docs) for creating instance
NSManagedObject *newEmployee = [[NSManagedObject alloc]
initWithEntity:employeeEntity
insertIntoManagedObjectContext:context];
i would like to know, is there any way to create an object similar to the above code using restkit
Note: i am using Restkit for creating object instance and mapping.
Thanks

Using Restkit you can use the static method object on the class you want to create. In your example
[ClassA object]
would return you an instantiated object.
Just be sure to import the correct headers:
#import <RestKit/CoreData.h>
instead of
#import <CoreData/CoreData.h>

No, you don't want to instantiate an NSManagedObject via alloc/init. You should use NSEntityDescription's insertNewObjectForEntityForName:inManagedObjectContext:. Something like:
ClassA *obj = [NSEntityDescription
insertNewObjectForEntityForName:#"ClassA"
inManagedObjectContext:context]; // ClassA is NSManagedObject Class
In order to have a NSManagedObjectContext, you also need an NSPersistentStoreCoordinator, and an NSManagedObjectModel, etc. Yeah, it's complex. This book really helped me get my head around Core Data; I recommend it wholeheartedly.
See the Core Data Programming Guide section on creating and deleting managed objects. Actually, while you're there, I'd recommend reading the entire Core Data Programming Guide. Core Data is amazing and powerful, but it is complex; you really want to know what you're doing.
Update: The fact that you're using RestKit might change what I said above. It may be that RestKit has it's own API for doing Core Data stuff, I'm not sure. Maybe check the docs.

Related

Mutable sets in NSManagedObjects?

The standard declaration for an autogenerated NSManagedObject property declares to-many relationships like this:
#property (nonatomic, retain) NSSet *somethings;
...
#dynamic somethings;
Would it be safe to change that declaration to an NSMutableSet? Would the CoreData component still function correctly?
Judging by the #dynamic, it probaby doesn't care if I use an NSSet subclass rather than an NSSet, but I don't want to rewrite a lot of code only to find out it doesn't work.
According to Apple's Core Data Programming Guide, this should always be declared as a NSSet.
If you want a mutable proxy (which is basically the mutable version of the core data set and works exactly the same) then you would use the function mutableSetValueForKey like this:
// myManagedObject is the managed object that has the somethings property.
NSMutableSet *mutableSomethings = [myManagedObject mutableSetValueForKey:#"somethings"];
mutableSomethings can then be modified as a standard NSMutableSet andsomethings will be updated and KVO methods will be appropriately called.
Note however, that many features of the mutable set (such as addSomethingsObject and removeSomethingsObject) are already provided in the core data generated accessors so in many cases you don't need to use the proxy.
You should keep it as an NSSet and do one of the following:
Use key value coding
Add the core data generated accessors
For key value coding, you'll access your collection like so:
NSMutableSet *somethings = [object mutableSetValueForKey:#"somethings"];
[somethings addObject:newObject];
For core data generated accessors, you'd add the following to your header:
#interface MyManagedObject (CoreDataGenerated)
- (void)addSomethingsObject:(MySomething *)object;
- (void)removeSomethingsObject:(MySomething *)object;
- (void)addSomethings:(NSSet *)somethings;
- (void)removeSomethings:(NSSet *)somethings;
#end
You do not need to implement these methods (Core Data will take care of it for you), and you can call them easily. This is my preferred way of handling collections because you get better type checking from the compiler.
The reason you should not change it to an NSMutableSet is because there is a good chance that you will cause crashes and/or that your changes will not be persisted into your Core Data store.
You may also want to look into mogenerator to help you out with creating all of your Cocoa classes.

What's the fastest and easiest way to create a new managed object?

When I have a subclass of NSManagedObject, I could do this:
Friend *newFriend = (Friend*)[[NSManagedObject alloc] initWithEntity:#"Friend"
insertIntoManagedObjectContext:moc];
But since I have a subclass, couldn't I simply instantiate it another way so that I don't have to tell it what Entity it is? (I mean: Is there already an predefined initializer for this, or must I write my own?)
Besides initWithEntity:insertIntoManagedObjectContext: the only two methods you can use to customize object initialization are awakeFromInsert and awakeFromFetch. See the full discussion related to Core Data object initialization here.

iPhone - Change entity class (NSManagedObject) to make them initializable

I would like to use my custom NSManagedObject like a normal object (as well as its regular functions). Is it possible to modify the class in order to be able to initialize it like a normal object?
[[myManagedObject alloc] init];
Thanks
edit: to clarify the question, will it screw everything up if I change the #dynamic with #synthesize in the implementation?
I do this quite often in one of my apps. My approach is to initialize the object with:
-(id)initWithEntity:(NSEntityDescription *)entity insertIntoManagedObjectContext:(NSManagedObjectContext *)context
passing nil for the context. To get the entity description, you do need access to the managedObjectContext. I tend to get the entity description when my app starts and then store it in an instance variable in my app delegate.
Here's an example:
//inside my "Engine" class
self.tweetEntity = [NSEntityDescription entityForName:#"Tweet" inManagedObjectContext:self.moc];
//later on when I want an NSManagedObject but not in a managed object context
Tweet *tweet = [[[Tweet alloc] initWithEntity:self.engine.tweetEntity insertIntoManagedObjectContext:nil] autorelease];
This allows me to use NSManagedObjects without storing them in a database. Later on, if I decide I do want the object inserted into my database, I can do it by inserting it into my managed object context:
[self.moc insertObject:tweet];
The managed object context is a required property of NSManagedObject therefore you can't properly initialize an instance of it without inserting it into a context. It looks at the context to understand it its entity and it notifies the context when any of its properties change.
The #dynamic and #synthesize are just compiler directives. You can switch to #synthesize from #dynamic as long as you provide proper getters and setters yourself. Since NSManagedObject relies heavily on key-value observing to function, you do have to write KVO compliant accessors.
If you need to initialize an NSManagedObject subclass, you override awakeFromInsert which will let you provide customization to the instance when it is created. You can also customized the object every time it is fetched using awakeFromFetch.

Can I create an new instance of my custom managed object class without going through NSEntityDescription?

From an Apple example, I have this:
Event *event = (Event*)[NSEntityDescription
insertNewObjectForEntityForName:#"Event"
inManagedObjectContext:self.managedObjectContext];
Event inherits from NSManagedObject. Is there a way to avoid this weird call to NSEntityDescription and instead just alloc+init somehow directly the Event class? Would I have to write my own initializer that just does that stuff above? Or is NSManagedObject already intelligent enough to do that?
NSManagedObject provides a method called initWithEntity:insertIntoManagedObjectContext:. You can use this to do a more traditional alloc/init pair. Keep in mind that the object this returns is not autoreleased.
I've run into the exact same problem. It turns out you can completely create an entity and not add it to the store at first, then make some checks on it and if everything is good insert it into the store. I use it during an XML parsing session where I only want to insert entities once they have been properly and entirely parsed.
First you need to create the entity:
// This line creates the proper description using the managed context and entity name.
// Note that it uses the managed object context
NSEntityDescription *ent = [NSEntityDescription entityForName:#"Location" inManagedObjectContext:[self managedContext]];
// This line initialized the entity but does not insert it into the managed object context.
currentEntity = [[Location alloc] initWithEntity:ent insertIntoManagedObjectContext:nil];
Then once you are happy with the processing you can simply insert your entity into the store:
[self managedContext] insertObject:currentEntity
Note that in those examples the currentEntity object has been defined in a header file as follows:
id currentEntity
To get it to work properly, there is a LOT of stuff to do. -insertNewObject:... is by far the easiest way, weird or not. The documentation says:
A managed object differs from other
objects in three main ways—a managed
object ... Exists in an environment
defined by its managed object context
... there is therefore a lot of work
to do to create a new managed object
and properly integrate it into the
Core Data infrastructure ... you are
discouraged from overriding
initWithEntity:insertIntoManagedObjectContext:
That said, you can still do it (read further down the page to which I linked) but your goal appears to be "easier" or "less weird". I'd say the method you feel is weird is actually the simplest, most normal way.
I found a definitive answer from More iPhone 3 Development by Dave Mark and Jeff LeMarche.
If it really bothers you that you use a method on NSEntityDescrpiton rather than on NSManagedObjectContext to insert a new object into an NSManagedObjectContext, you can use a category to add an instance method to NSManagedObjectContext.
Create two new text files called NSManagedObject-Insert.h and NSManagedObject-Insert.m.
In NSManagedObject-Insert.h, place the following code:
import <Cocoa/Cocoa.h>
#interface NSManagedObjectContext (insert)
- (NSManagedObject *)insertNewEntityWithName:(NSString *)name;
#end
In NSManagedObject-Insert.m, place this code:
#import "NSManagedObjectContext-insert.h"
#implementation NSManagedObjectContext (insert)
- (NSManagedObject *)insertNewEntityWithName:(NSString *)name
{
return [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:self];
}
#end
You can import NSManagedObject-Insert.h anywhere you wish to use this new method. Then replace the insert calls against NSEntityDescription, like this one:
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
with the shorter and more intuitive one:
[context insertNewEntityWithName:[entity name]];
Aren't categories grand?

Can I encode a subclass of NSManagedObject?

This is for an iPhone App, but I don't think that really matters. I need to send a custom object (which is managed by Core Data) over bluetooth using the iPhone's GameKit. Normally, I would just use an NSKeyedArchiver to package up the object as a data object and ship it over the line, then unarchive the object and I'm done. Of course, I would need to implement the initWithCoder: and encodeWithCoder: methods in my custom object as well.
I'm not sure if this can be done with an NSManagedObject class, which is managed by Core Data or not. Will they play nice together? I'm guessing once I ship the encoded managed object over to the other device and unencode it, I would just add this received object to the other device's context. Is this correct? Am I missing any steps?
An NSManagedObject instance can't meaningfully exist outside of an NSManagedObjectContext instance, so I wouldn't bother trying to do the NSCoding dances required to directly serialize and deserialize an NSManagedObject between two contexts (you can do this; see below). Instead I would create a dictionary with the appropriate attribute key/values (you can get the attribute names via the managed object instance's attribute names via instance.entity.attributesByName.allKeys (you can use [instance dictionaryWithValuesForKeys:keys] to get the dictionary of attribute:value pairs) . I would send relationship information as NSURL-encoded NSManagedObjectIDs. Don't forget to include the instance managedObjectID (as an NSURL) in the dictionary so that you can reconnect any relationships to the object on the other end. You'll have to recursively create these dictionaries for any targets of relationships for the instance you're encoding.
Then send the dict(s) across the wire and reconstitute them on the other end as instances in a new managed object context (you can use setValuesForKeysWithDictionary:).
You may notice that this is exactly what the NSCoder system would do for you, except you would have to use the classForCoder, replacementObjectForCoder: and awakeAfterUsingCoder: along with a custom NSDictionary subclass to handle all the NSManageObject-to-NSDictionary mapping and visa versa. This code is more trouble than it's worth, in my experience, unless you have a complex/deep object graph that you're trying to serialize. For a single NSManagedObject instance with no relationships, it's definitely easier to just do the conversion to a dict and back yourself.
This sounds like a job for TPAutoArchiver.
I suggest the dictionary solution for simpler options. However, here is how I solved the issue. My model was already sizable and robust, with custom classes and a single root class above NSManagedObject.
All that I needed was for that single class to call the appropriate designated initializer of NSManagedObject: [super initWithEntity:insertIntoManagedObjectContext:]. This method, and the metadata in an NSEntityDescription is what sets up the implementations of all the dynamic accessors.
- (id)initWithCoder:(NSCoder *)aDecoder {
CoreDataStack *cds = [LibraryDiscoverer unarchivingCoreDataStack];
NSEntityDescription *entity = [cds entityDescriptionForName:[[self class] entityName]];
NSManagedObjectContext *moc = [cds managedObjectContext];
self = [super initWithEntity:entity insertIntoManagedObjectContext:moc];
self.lastEditDate = [aDecoder decodeObjectForKey:#"lastEditDate"];
return self;
}
The CoreDataStack is my abstraction around CoreData. The LibraryDiscoverer is a global access hook to get hold of the core data information. The entityName is a method defined to provide the entity name from the class name; if you follow a naming convention (i.e. class name = entity name) it can be implemented generically.
All the other initWithCoder: methods in my class hierarchy are standard NSCoder, with the note that you don't need to encode both directions of a relationship, CoreData reconnects that for you. (As it always does, including with the dictionary solution.)