1

Say I have a subclass of NSManagedObject called MBManagedSquare and MBManagedCircle. An MBManagedSquare and MBManagedCircle define a method prepareFromDictionary:(NSDictionary*)dic, and both of their implementations are different.

Say I have this code:

NSString *type = // could be @"MBManagedSquare" or @"MBManagedCircle"
NSEntityDescription *desc = [NSEntityDescription entityForName:type inManagedObjectContext:_context];
NSManagedObject *object = [[NSManagedObject alloc] initWithEntity:desc insertIntoManagedObjectContext:_context];

So the type of entity it will be with Core Data is determined dynamically via a type string. So all I know is that it is an NSManagedObject.

What I want to do is call the prepareFromDictionary: method for the right class.

So if the type is "MBManagedSquare", I want to cast the object to an MBManagedSquare, and then call

[castedObject prepareFromDictionary:dic];

What I tried doing is:

Class class = NSClassFromString(type);
class *castedObject = (class*)object;

but I get an expected expression error. I'm not sure if this is even possible. How would I do this?

justin
  • 104,054
  • 14
  • 179
  • 226
Snowman
  • 31,411
  • 46
  • 180
  • 303
  • 1
    You're casting an iVar to an iVar. That's wonky. Use uppercase Class in the cast, and get rid of the dereferencing operator (*). Of course the point is moot, considering all objects respond to `-class` – CodaFi Nov 12 '12 at 05:40
  • @CodaFi this doesn't work either: `Class class = NSClassFromString(type); class *castedObject = (Class)object;` – Snowman Nov 12 '12 at 14:58

2 Answers2

2

You don't need to worry about calling the right class if the selectors and their parameters match -- ObjC has plenty of dynamic dispatch powers.

As far as an implementation, it's pretty common to either:

  • create a common base with the interface you want
  • or create a protocol which both classes adopt:

MONProtocol.h

@protocol MONManagedShapeProtocol < NSObject >
- (void)prepareFromDictionary:(NSDictionary *)pDictionary;
@end

then (since you know it is one of the two types, MBManagedSquare or MBManagedCircle) either derive from the base or adopt the protocol and declare your variable like:

// if subclass
MBManagedShape * castedObject = (MBManagedShape*)object;

or

// if protocol
NSManagedObject<MONManagedShapeProtocol>* castedObject =
                        (NSManagedObject <MONManagedShapeProtocol>*)object;
justin
  • 104,054
  • 14
  • 179
  • 226
  • But how would it know which to call using the subclass technique? MBManagedShape in your example is the superclass correct? The Circle and the Square class have different implementations for prepareFromDictionary though, so the correct method has to be called. – Snowman Nov 12 '12 at 14:56
  • 1
    So actually it turns out that using Core Data, when I init an entity with an entity description like `[NSEntityDescription entityForName:@"MBManagedCircle" inManagedObjectContext:_context]`;, the returned object is automatically casted to the correct type. How convenient! – Snowman Nov 12 '12 at 15:08
  • @mohabitar a) you don't need to know; the implementation to use is matched with the instance you message. dynamic dispatch. b) yes c) each class may implement it differently. – justin Nov 12 '12 at 18:59
0

no need for a cast there. the object can be either or and the function is only there once. checking if it is there is good: respondsToSelecctor:@selector(prepareFromDictionary:)

Daij-Djan
  • 49,552
  • 17
  • 113
  • 135