I have a Core Data model where I have an entity A, which is an abstract. Entities B, C, and D inherit from entity A. There are several properties defined in entity A which are used by B, C, and D.
I would like to leverage this inheritance in my model code. In addition to properties, I am wondering if I can add methods to entity A, which are implemented in it's sub-entities.
For example:
I add a method to the interface for entity A which returns a value and takes one argument
I add implementations of this method to A, B, C, D
Then, I call executeFetchRequest: to retrieve all instances of B
I call the method on the objects retrieved, which should call the implementation of the method contained in B's implementation
I have tried this, but when calling the method, I receive:
[NSManagedObject methodName:]:
unrecognized selector sent to instance
I presume this is because the objects returned by executeFetchRequest: are proxy objects of some sort.
Is there any way to leverage inheritance using subclassed NSManagedObjects?
I would really like to be able to do this, otherwise my model code would be responsible for determining what type of NSManagedObject it's dealing with and perform special logic according to the type, which is undesirable.
Any help is appreciated, thanks in advance.
It should work. The objects returned by executeFetchRequest: are real instances of NSManagedObjects (or subclasses thereof.)
The steps to use custom classes in CoreData are as follows. Say you have entities A and B, where B inherits from A.
Then you need two custom classes as
#interface A:NSManagedObject{
}
-(void)someMethod:(NSString*)a;
#end;
#interface B:A{
}
-(void)someMethod:(NSString*)a;
#end;
Then set them in the XCode data modeler as shown:
This way, the CoreData automatically assigns the correct class to the NSManagedObject when it is fetched from the database.
If you're getting that exception, it means Core Data is not using your custom class. The key here is NSManagedObject -- that's the object Core Data created for the objects in your data store.
If you haven't already, you'll need to create a class that inherits from NSManagedObject, add your custom methods there, and then set entity A to use your custom class in the object model tool. If entities B, C, D, etc. have specific behaviors, you should subclass the class you created for entity A and assign those entities to use the subclasses too.
Essentially, you have a parallel hierarchy: one hierarchy of entities, and another of classes. You'll likely end up with entity X and class X for each entity in your object model.
After trying lots of solution calling isMemberOfClass on my NSManagedObject subclass before trying to use my custom method made the trick.
[thing isMemberOfClass:[Thing class]];
[thing customMethod]; //was getting unrecognized selector sent to instance here before
I had this same error for the same underlying reason, but it came about in a different situation and a different cure. Your suggestion helped me a lot!
Originally I had created my class implementing my entry by hand. I didn't know there was an Xcode menu for this. I think the link was never there! So it wasn't until I had added and began testing the new custom methods (not setter/getters) that I started to get the error.
My solution was to change the name of my class, have Xcode re-create the class for my entry via Editor->Create NS Mangage Object.... Then cut and paste in the old code into the new class. No difference in code!
Xcode seems to have some kind of internal link that is not apparent in the code.
Related
I am in the process of building a Cocoa app, which is comprised of a window divided in 3 sections. Each section is responsible for its own business and there are around 30 controls in it between table views, pop up buttons etc.
I started with a single Controller but things get messy pretty easily, so I decided to break the logic down in 3 controllers object (one each section of the view). I then created the NSObject reference on Interface Builder and hooked up all the outlets, actions, data sources and delegates. So far so good.
Now, the three sections pass objects to each other and therefore I need a way to set an object from one class to another. The object in question is a class variable, but as I have no reference to the object I don't know how to pass it around.
Is there a way to do this or is this just the wrong approach overall?
Solution:
As Sergio mentioned below in one of the comments, the solution seems to be to create a weak reference to the other controllers inside each controller as IBOutlet and then in the Xcode Interface Builder link the controller objects together. As a result, now each controller can access the exposed methods and variables of the referenced controllers.
Now, the three sections pass objects to each other and therefor I need a way to set an object from one class to another. The object in question is a class variable, but as I have no reference to the object I don't know how to pass it around.
What seems missing in your design is a Model (as in Model-View-Controller). This would be a class encapsulating all the state of your app, even if it is transitory state, so that each affected object have access to it.
One easy implementation for such a model class is a singleton, so that it is readily available in all of your controllers. Have a look here for some thought about the implementation of a singleton in Objective-C.
Once you have your model class, your controllers could access it like this, e.g.:
[MyModel sharedModel].myObject = ...;
This approach is good, IMO, if it makes sense for you to go in the direction of creating a Model for your design. This depends on the semantics of the object that your controllers share. So, there might be alternative solutions better fit for your case. E.g., one controller could be the owner of the shared object, and the other two could receive a reference to the first controller on init so that they can access its public properties.
I have a data model for Formula 1 races with 3 entities:
RacingActor: Abstract entity
Pilot: inherits from RacingActor
Team: inherits from RacingActor
If I generate NSManagedObject subclasses to represent these entities, the code generated doesn't represent at all this design:
Everything inherits from NSManagedObject
Nothing prevents me from instantiating RacingActor
The team property in Pilot is of type NSManagedObject instead of Team
Is this the expected behaviour? Am I supposed to fix the code generated by Xcode? Am I missing something?
BTW, I'm using Xcode 4.3.3
Core Data at the core is an object relational mapping library. Long time ago it was called Entreprise Object Framework, part of WebObjects.
So yes, the base object for any persistant object managed by Core Data is NSManagedObject, and you can do whatever you want with them.
In your example, Team and Pilot will share a common table, and you'll be able to use queries to retrieve Teams and Pilots at once. That's the idea.
The Objective-C inheritance tree (if you use custom classes) can mirror the model you defined, but it doesn't need to. You can create a custom RacingActor class, use it as a base class for custom Team and Pilot classes, or you can tell the model to use RacingActor for Team and Pilot objects. You can even define a completely unrelated base class (provided NSManagedObject is a parent, directly or indirectly) for Team and / or Pilot if you want to.
You are then free to implement the specific behaviors you need in your business logic, either in controllers or in custom data classes.
I got answer about Foundation magic for this question: What's the most *simple* way to implement a plain data object which conforms key-value-observing?
What's the magic? How it work internally? Because it's dangerous using framework which I can't understand its internal behavior, I want to know its behavior. Currently, I cannot understand how it work without any method definitions.
Apple's documentation describes how KVO is implemented internally.
The gist of it is that when you register an observer on an object, the framework dynamically creates a subclass of the object's original class, and adjusts the object to appear as an instance of this new dynamic class. You can see this if you inspect an object in the debugger after it has had an observer registered.
This new class intercepts messages to the object and inspects them for those matching certain patterns (such as the getters, setters, and collection access).
In a nutshell: Objective-C 2.0's #property declaration creates accessor methods for the named property, so there are method definitions. #property is just a shorthand way to define them which avoids a lot of repetitious boilerplate code.
When you observe a property, a private subclass is created which implements accessors that call the appropriate notification methods before and after changing the property value. A technique known as "isa swizzling" is then used to change the class of the observed object.
I've taught myself Obj-C, and have been self-teaching Cocoa, but adding Core Data to my program has given me nothing but a huge headache, thanks to me needing extensive custom logic. Here are a couple of the questions that are driving me insane.
What if I want a Managed Object to own another Managed Object? It seems if I give it a to-many relationship, the owned object will simply be shared by various masters, but I want each Owner to have its own.
If I subclass an NSManagedObject, can I make simple calls to the Array Controller to remove or copy instances of ManagedObject, and assume those will be translated into the Core Data model?
If I want to programmatically edit the properties of a ManagedObject, can I get away with mere KVC calls to the Array Controller? What's all this talk about NSPredicate an NSFetchRequest to the NSManagedObjectContext from the NSManagedDataStoreDrivingMeCrazy? Can I make an NSFetchRequest that filters the relationships of an object currently selected in a table view?
Once I use a fetch request to get a group of objects, how do I go about querying their relations? Does that require a whole other FetchRequest, Predicate, and so forth? Isn't Core Data supposed to be easier? Am I missing something?
An entity is similar to a class--it's a blueprint for a managed object that will be instantiated later. Each managed object will have its own attributes and relationships to configure.
You can definitely insert and delete managed objects. You might have to do some code to support copying, but I am not sure.
Yes, the properties (attributes and relationships) of managed objects support KVC (and KVO and bindings).
You can access the object or set of objects simply by using the relationship name that you define in the model (no additional fetch or logic is required).
After reading the Key-Value Coding Programming Guide, the Key-Value Observing Programming Guide and the Model Object Implementation Guide, as well as reading many StackOverflow entries on the topic and experimenting with various modelling scenarios, I feel like I have a good grasp on how to model my data.
I end up using declared properties for all my attributes and to-one relationships, backed by private ivars. For read-only attributes which need to be privately writeable, I use the readonly attribute in the .h interface declaration, then re-declare the property with the readwrite attribute in a class extension declared in the .m file. Inside the class methods, I always use the property accessors with the dot syntax and never access the private ivars directly.
There is however one aspect which still leaves me puzzled: how to properly model to-many relationships, especially when the collection is to be publicly immutable, but privately mutable (i.e. consumers of the model object cannot add or remove objects to the collection, but the collection's content is managed privately by the class).
I do understand how to implement the KVC accessor methods for to-many relationships (countOf<Key>, objectsIn<Key>AtIndex, etc.) and this is the route I've been following so far.
However, I've seen some sample code that uses declared properties to expose the relationships, do not implement the KVC accessor methods, yet are still Key-Value observable. For example:
#interface MyModel : NSObject
{
// Note that the ivar is a mutable array,
// while the property is declared as an immutable array.
#private NSMutableArray *transactions_;
}
#property (nonatomic, retain, readonly) NSArray transactions;
#end
--------------------
#implementation MyModel
#synthesize transactions = transactions_;
- (void)privateMethodThatManagesTransactions
{
[[self mutableArrayValueForKey:#"transactions"] addObject:t];
}
#end
If a consumer object adds itself as an observer of a MyModel instance for the "transactions" key path, it will be notified whenever transactions are added or removed from the transactions collection (as long as the mutations are done via the mutableArrayValueForKey: method).
To me, this seems like the cleanest way to expose to-many relationships as I don't need to hand-code the collection KVC accessors and it keeps the code clean.
However, it doesn't seem to be the way that is promoted by the Apple documentation, and I can't help but wonder if the fact that it works is only an unreliable side-effect.
So before commiting to one technique or the other in my real-life model classes for a project I'm beginning to work on, I'd like to get the opinion and advice of experienced Cocoa developers.
So the question is: if I use properties to model to-many relationships, do I still need to implement the KVC accessor/mutator methods?
Update
Even when I declare a to-many property as readonly, like in the example above, external code can still call mutableArrayValueForKey:#"transactions" on the model object and mutate the collection. This seems to indicate that using declared properties for to-many relationships isn't the way to go, but I still feel like I don't quite get it...
Yes.
There is however one aspect which still leaves me puzzled: how to properly model to-many relationships, especially when the collection is to be publicly immutable, but privately mutable ….
Easy: Declare the property as readonly in the header, then redeclare it as readwrite, copy in a class extension in the implementation file.
I do understand how to implement the KVC accessor methods for to-many relationships (countOf<Key>, objectsIn<Key>AtIndex, etc.) and this is the route I've been following so far.
There are mutative ones, too. With these, you don't need to use mutableArrayValueForKey:; instead, you can use the mutative accessors directly. You'll still get KVO notifications, because KVO wraps those methods the first time something adds itself as an observer for the property.
I have a list of the accessor selector formats, including the mutative accessors, on my blog.
Edit:
Even when I declare a to-many property as readonly, like in the example above, external code can still call mutableArrayValueForKey:#"transactions" on the model object and mutate the collection.
This is a good reason to make it a habit to use the mutative accessors and avoid mutableArrayValueForKey:. You won't send mutation messages from outside the class if you get a compiler warning (no such [public] method) any time you try it.
Despite the availability of mutableArrayValueForKey: and the risk that someone will use it, KVO-compliant properties are the way to go here.