Search code examples
ioscore-datansmanagedobjectnsmanagedobjectcontext

Trying to dynamically create an NSManagedObject subclass based on NSString value in iOS


I am building an application that utilizes Core Data, which has multiple entities in the Data Model. What I would like to do is create a method which is able to create the appropriate subclass of NSManagedObject based on the name that the method it receives, which would be an NSString.

My method looks like this:

- (NSManagedObject *) addEntity:(NSString *)name {

  NSManagedObjectContext *context = [self managedObjectContext];
  NSError *error;

  //need to add a line here that casts EntityType to of type "name" which is passed into the method.
  EntityType *testEntity = [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:context];

  [context save:&error];

   return testEntity;

}

Where "EntityType" is of type "name", such that if I pass the name "Manager" into the method, I will create an object of type "Manager". Therefore the above line:

EntityType *testEntity = [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:context];

would read:

Manager *testEntity = [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:context];

What do I need to do in order to dynamically create Entities based on the type that I pass into the method? Please note that I am doing this because I have over twenty entities in my application and would like to have just one method that I can use for any of them.


Solution

  • If your issue is the type of testEntity just use a generic NSManagedObject

    Anyway a nice solution would be to add a category over NSManagedObject. Here's an implementation which basically replicates the same functionality provided by MagicalRecord.

    NSManagedObject+Utilities.h

    @interface NSManagedObject (Utilities)
    + (instancetype)my_createAndSave:(NSError **)error;
    @end
    

    NSManagedObject+Utilities.m

    @implementation NSManagedObject (Utilities)
    + (instancetype)my_createAndSave:(NSError **)error {
        NSString *entityName = NSStringFromClass(self);
        if ([self respondsToSelector:@selector(entityName)]) {
            entityName = [self performSelector:@selector(entityName)];
        }
        NSManagedObject *entity = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:self.managedObjectContext];
        [self.managedObjectContext save:error];
        return entity;
    }
    @end
    

    A few remarks:

    • Naming:

      • being a category is always preferable to add a custom prefix, not to clash with Apple's API. I used my_ here, but you can add whatever you like.
      • starting the method name with new should be reserved to method returning a non autoreleased object. Since entity is autoreleased, ARC will add an extra retain before returning the object (balanced later by a release) (reference). While this is not an issue, it breaks the standard naming conventions and should be avoided.
    • Error handling

      • you should either yield the error or handle it properly. I chose to pass the error back to the caller in my implementation