What is the best way to add custom methods to my core data generated classes?
For example, say I have a "Person" entity with properties "firstname" and "lastname". I wish to add a "fullname" method, which returns a concatenation of the firstname and lastname properties.
I could add the method to the generated .h and .m files, but this would be difficult to maintain during development when my entities may still change. Recreating the .h and .m file would overwrite these changes. Another idea is to subclass the generated class and add the methods there.
Is there a better way?
I find that the best way to add custom methods that aren't directly tied to data properties is to use a category. This generally works best if you create your Core Data entities as their own subclasses of NSManagedObject in the data modeler, but it can work without that as well. This way all the machine generated code can stay in the main .h and .m files, and all your custom code goes in the .h and .m for your category on that class.
I'd recommend adding these methods to your custom NSManagedObject subclass. If you're worried about maintaining accessors as your data model changes, while preserving your custom methods, I'd suggest looking to "Wolf" Rentzsch's mogenerator. Many people swear by this tool for just this purpose.
You create your own subclass of NSManagedObject for the entities.
Better explained in the NSManagedObject documentation
Related
Another architecture question.
I have a custom class calle Airfield. Let's say it has 2 ivars, name and tower frequency.
It's in a class called Airfield with a .h and .m file.
Problem is, I want to read a whole bunch of airfields from an XML file and give them to a controller for a table view.
Should I create a new class called airfielddb which imports airfield for the single object definition and reads the XML creating an array of airfield objects?
Or do I declare an array as an ivar in Airfield.h?
I am really struggling with some of these OO Modeling type questions. Your help is very much appreciated.
Neither of this.
You should keep Airfield class as is- it's your model.
There is no need in creating AirfieldDB class as well. You are loading data for tableview, and then you should implement the loading in your class implementing UITableViewDataSource
which could be possibly your ViewController.
You can also check the nice example at:
Apple's Table view Programming guide(listing 4-6)
I'm using an xcdatamodel to define a number of classes based upon CoreData data entities. This is working great and I can retrieve them in accordance to Apple's examples:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdFetching.html
What I'm after however, is a way to package the fetch method up into another class, but I have a couple of questions...
e.g.
MyDataAccessClass *mdac = [[MyDataAccessClass alloc] init];
myFetchedData = [mdac fetchData];
Q1. If I do this, is it ok that the NSManagedObjectContext is defined in the class? or does it still need to be referenced in my view controller and passed to my 'MyDataAccessClass'?
Q2. It makes sense to me to have the data retrieval methods set up in the classes created by XCode for the entities in the data model. Although every time I try to do this, then update those classes automatically because they are automatically generated by XCode, they overwrite any methods I've defined.
Thanks in advance!
You might be able to create a new NSManagedObjectContext in the seperate class - not sure if there will be any issues with that since one is already created in the appDelegate. What I did was what you suggest in the second part of Q1, where I pass the NSManageObjectContext into the seperate method class so then I can do something like:
myFetchedData = [mdac fetchData:currentNSManagedObjectContext];
I'm looking through the PageControl example from Apple. They have a class called ContentController. In a subclass of the class, PhoneContentController.m, they have this:
#interface ContentController (PrivateMethods)
- (void)loadScrollViewWithPage:(int)page;
- (void)scrollViewDidScroll:(UIScrollView *)sender;
#end
Is this adding a category to the class ContentController?
Why would they put it in this file, versus the original file they created?
By declaring it in the PhoneContentController.m file, does it give this class access without having any additional directives for the compiler?
(I'm trying to understand the OOAD principles and why Apple does certain things in their example code, hierarchies, etc). Thanks!
Is this adding a category to the class ContentController?
Yes, they are adding a category.
Why would they put it in this file, versus the original file they created?
If I recall correctly, this is done because there are two UIs, (one for iPad and one for iPhone,) so that they can write the code only once and use the same handlers in the different view controllers.
By declaring it in the PhoneContentController.m file, does it give this class access without having any additional directives for the compiler?
Well, yes. It's a small matter to compile an additional 4 line file, and I think this is a template related decision rather than a compiler related one. It's simpler to distribute, say, 3 sample files instead of 4, for example.
Exactly as the title says, why does Core Data create instances of NSManagedObject with properties for each entity's attribute, but no accompanying instance variable? The problem is, I would like to use some of my 'Entities' in a typical alloc/init style fashion in some parts of my code. Not using Core Data's fetching/context to create/store.
I suppose I could stay without the instance variables, but would it hurt to add them? Can I also change the #dynamic to #synthesize so I can use KVC on my properties/ivars?
Perhaps I'm completely wrong in trying to use one of my Core Data entities in some parts of my code without using the core data APIs. Still rather new to it to understand when I can go my own route.
The reason it doesn't use ivars is that that data isn't there. When you load an object it may not fault in all of its data. ivars are just variables, if you and write to them NSManagedObject doesn't have a chance to fault in the value if it has not been loaded yet. Via accessors NSManagedObject has a choke point that allows it to read the data off the disk if it has not been faulted in yet, which means your object graph can be brought in lazily. Otherwise you would need to bring in every connected object.
Because of that, you can't just add ivars, they won't have the values you want. Likewise you can't change from #dynamic to #synthesized, things will not behave correctly. The dynamic property implementations provided by CoreData are completely KVC and KVO compliant anyway.
If you want to access the values without tripping KVO or KVC you can access the "primitive" values. You do that in one of two ways. You use primitiveValueForKey: and setPrimitive:valueForKey: or you can just declare the primitive and let CD provide dynamic implementations (from the documentation)
#interface Department : NSManagedObject
{
}
#property(nonatomic, retain) NSString *name;
#end
#interface Department (PrimitiveAccessors)
- (NSString *)primitiveName;
- (void)setPrimitiveName:(NSString *)newName;
#end
You don't need instance variables with Core Data. A managed object stores these values elsewhere.
I've never gotten very far with Core Data, but if I remember correctly, you're supposed to use primitiveValueForKey: and setPrimitiveValue:forKey: to perform these accesses from your accessor methods. (Outside of your accessors, you should be using either the accessors themselves or valueForKey:/setValue:forKey: instead.)
Update: mogenerator works, with a template modification
The Core Data documentation suggests using the -primitiveValue and -setPrimitiveValue: methods to access and change internal data of an NSManagedObject subclass rather than the slower and non-type-checked -primitiveValueForKey: and setPrimitiveValue:forKey:.
I would like to adopt this change in my code but in order to avoid compiler warnings I need to add #property and #dynamic declarations to my managed object classes for all those primitive accessors. Xcode is happy to generate all that code for me, but only for the public accessors to the object (-value rather than -primitiveValue).
Is there any automated method, either through Xcode or an external program that can scan the .xcdatamodel file, to generate those primitive accessors for me so I don't have to type them all out in all 16 of my managed classes?
Have a look at mogenerator (GitHub).