Trying to dynamically create an NSManagedObject su

2019-09-02 13:27发布

问题:

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.

回答1:

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