PDA

View Full Version : Core Data : How to use accessors and properties




Amuraivel
Aug 30, 2010, 02:36 AM
Many of you who use Core Data know that you can change properties of managed objects with KVC syntax:

FUNCTIONING: [newTest setValue:[NSString stringWithUUID] forKey:@"uuid"];

I would like to use the Obj-C 2 accessors to modify properties of the form:

aManagedObjectAttribute = aValue;


BROKEN: newTest.uuid = [NSString stringWithUUID];

If I use this syntax, it throws a compiler error of the genre: Property 'uuid' not found on object of type 'NSManagedObeject *'


According to the documentation, I am supposed to add accessors in either a Category or as a MO subclass.


I have downloaded a few examples, and cannot figure out where I should put these accessors. By including the category as a header, I can avoid the compiler error, but then I get a:

-[NSManagedObject setUuid:]: unrecognized selector sent to instance 0x1002428f0

How should I implement the obj-C 2 standard in a practical sense? (i.e. where should I put the files? When/where do I include the headers; How do you use the categories for the modeled object graph?)



jared_kipe
Aug 30, 2010, 12:11 PM
Core Data is more like a NSDictionary

It is difficult for me to explain, but you cannot add properties for every key unless you know what EVERY key would be named.

In you example, you COULD add a category with the method
- (void)setUuid: (NSString *)uuid {
[self setValue:[NSString stringWithUUID] forKey:@"uuid"];
}

And thus use the dot syntax, but you need to do so for EVERY key you would ever use.

EDIT: Maybe I didn't make it clear enough, only adding @property and @synthesize/@dynamic will NOT be enough because you don't need an instance variable named uuid, you need to actually call a very specific method.

Amuraivel
Aug 30, 2010, 02:49 PM
Thanks for the tip.

The documentation says that I supposedly can use the @property / @dynamic scheme for še accessors.

I tried adding a category, but didn't know exactly how to include it with the data model, I could solve the compiler errors, but still would get a debugger invalid accessor thrown error.

I really can't figure out where/how I should include accessor code so it works with

Xcode really just needs a switch to enable accessors, especially after they went through all the trouble of adding this to the Obj-C 2.

jared_kipe
Aug 30, 2010, 03:27 PM
To what documentation are you referring?

I don't think you quite understand some of the principals going on here.

You could subclass NSManagedObject or add a category to it, HOWEVER you would NOT be needing to add instance variables to NSManagedObject, you would simply be adding some convenience oriented methods to call the -setValue:forKey: method of NSManagedObject

There is no "switch" to enable accessors, the @property features are language constructs and have very little to do with Xcode itself.

To put it more bluntly
someObject.someProperty = someOtherObject;
is the same thing as
[someObject setSomeProperty: someOtherObject];
Which is effectively coded like this:

- (void) setSomeProperty: (id) object {
[object retain];
[someProperty release];
someProperty = object;
}


BUT YOU DO NOT WANT THAT!! You want something like..

- (void) setSomeProperty: (id) object {
[self setValue: object forKey: @"someProperty"];
// or super in the case of a subclass
}



There is no way for Objective-C or Xcode or anything else to just generate this code for you. There is no switch to flip, there is no easier way. The @property syntax cannot GUESS you intentions and make a subtly different method.

vocaro
Aug 30, 2010, 06:13 PM
The documentation says that I supposedly can use the @property / @dynamic scheme for še accessors.

True; I use them all the time.

I tried adding a category

Why in the world are you using categories? Just use plain old interfaces and classes. Look in CoreDataBooks (http://developer.apple.com/iphone/library/samplecode/CoreDataBooks/Introduction/Intro.html) for an example, especially the Book.h/Book.m files.

chown33
Aug 30, 2010, 06:31 PM
See this reference doc:
http://developer.apple.com/mac/library/documentation/cocoa/conceptual/objectivec/articles/ocProperties.html

Find the description of @dynamic:

@dynamic
You use the @dynamic keyword to tell the compiler that you will fulfill the API contract implied by a property either by providing method implementations directly or at runtime using other mechanisms such as dynamic loading of code or dynamic method resolution. It suppresses the warnings that the compiler would otherwise generate if it can’t find suitable implementations. You should only use it if you know that the methods will be available at runtime.
The example shown in Listing 5-3 illustrates using @dynamic with a subclass of NSManagedObject.
Listing 5-3 Using @dynamic with NSManagedObject
@interface MyClass : NSManagedObject
{
}
@property(nonatomic, retain) NSString *value;
@end

@implementation MyClass
@dynamic value;
@end
NSManagedObject is provided by the Core Data framework. A managed object class has a corresponding schema that defines attributes and relationships for the class; at runtime, the Core Data framework generates accessor methods for these as necessary. You therefore typically declare properties for the attributes and relationships, but you don’t have to implement the accessor methods yourself, and shouldn’t ask the compiler to do so. If you just declared the property without providing any implementation, however, the compiler would generate a warning. Using @dynamic suppresses the warning.

Underline added for emphasis.


If the docs still aren't enough to solve the problem, then post your malfunctioning code.
We need to see the actual class implementation section, not just the malfunctioning uses of it.

Amuraivel
Sep 14, 2010, 08:58 AM
I just wanted to give a bit of feed back having sort of solved the problem.

I solved the problem with a category:

ManagedObjectAccessors.h

@interface NSManagedObject (ManagedObjectAccessors)
//COMMON
@property(readwrite,nonatomic,retain) NSManagedObject *nodeParent;
@end

@implementation NSManagedObject (ManagedObjectAccessors)
@dynamic nodeParent;
@end


NB:Even if this is declared in the <AppName.pch> global includes file, it must be declared each class file to get Xcode to compile correctly.

I still wish these declarations were generated automatically with the basic Core Data setup…

vocaro
Sep 19, 2010, 06:28 PM
I solved the problem with a category:

ManagedObjectAccessors.h

@interface NSManagedObject (ManagedObjectAccessors)


I still have no idea why you insist on using categories to solve this problem. None of the Core Data sample code uses categories for this.


@property(readwrite,nonatomic,retain) NSManagedObject *nodeParent;


Note that the type of your property is a raw NSManagedObject, which provides no type safety and no hint to users about the property's type.


I still wish these declarations were generated automatically with the basic Core Data setup…

They are! Go to your data model. Select an entity. Choose File > New File, then Managed Object Class and keep clicking Next. This will generate a complete class with the properties for you.

This is all described in the documentation.