编辑:这个downvoting syndrom在这里吸引了大量时间。我问了一个问题,我认为我做了我的作业,并征求意见。上调的答案意味着编写时间警告,而我自己的,可能是最干净的OOP方式没有任何兴趣。
简要概述,以便了解我为什么需要这个以及我尝试做什么:我正在编写一个实现数据映射器模式的ORM。映射器(即用于SQLite结果)必须使用基本实体类的初始化器创建实体类的子类。所以有问题。
映射器不会,也不应该知道特定的类。不同数据源的映射描述和特定映射器都是从实体类中抽象出来的,并且是实体描述的设计部分。
实体类似于NSManagedObject,但ORM遵循不同的模式。创建任何实体的描述类似于NSEntityDescription(但也遵循不同的模式和目的)。
所以我的目标是使用ManagedEntity的init方法创建我知道是ManagedEntity子类的实体。
所以我的mapper的init看起来像这样:
- (id)initWithEntityClass:(Class)EntityClass entityDescriptor:(EntityDescription*)entityDescriptor
{
self = [super init];
if (self)
{
_EntityClass = EntityClass;
_entityDescription = entityDescription;
... (assert that class is of subclass of ManagedEntity)
}
稍后在我的映射器中,我想创建具体的实体:
-(void)createEntityWithSQLiteResultSet:(sqlite3_stmt*)resultSet
{
// Problem: How to init a class known to be a subclass of ManagedEntity?
ManagedEntity *newEntity = [[_EntityClass] alloc] initWithEntityDescription:_entityDescription];
}
那么如何使用ManagedEntity的init创建ManagedEntity的子类?
当然,我可以使用respondsToSelector()来执行initWithEntityDescription并调用它。但是有些东西告诉我应该有一种更优雅的方式,类已经知道了。此外,respondsToSelector和selector调用仅执行运行时检查。即使实体初始化程序不应该更改,但如果此方法存在,则丢失编译时检查似乎是一个糟糕的选择。
答案 0 :(得分:5)
作为映射的一部分,您必须知道所需的子类。然后使用
ManagedEntity *newEntity = [[NSClassFromString(className) alloc] initWithEntityDescription:_entityDescription];
编辑:
正如我所承诺的那样,我正在GitHub项目中构建它,并意识到为什么它可能无法编译。您必须在范围内可访问的已知类中声明-initWithEntityDescription:
。在这种情况下,这意味着您必须声明并实现ManagedEntity -initWithEntityDescription:
并且在文件顶部有“#import”ManagedEntity.h“。
答案 1 :(得分:0)
强化Neal的正确答案,即OP声称无法工作,因为他知道objC:)
#import <CoreData/CoreData.h>
@interface TestMapper : NSObject
- (NSManagedObject*)createClassForEntity:(NSEntityDescription*)entity context:(NSManagedObjectContext*)ctx;
@end
#import "TestMapper.h"
@implementation TestMapper
- (NSDictionary*)entityToClassMap {
return nil; //TODO ;)
}
- (NSManagedObject*)createClassForEntity:(NSEntityDescription*)entity context:(NSManagedObjectContext*)ctx {
NSString *className = self.entityToClassMap[entity.name];
assert(className);
return [[NSClassFromString(className) alloc] initWithEntity:entity insertIntoManagedObjectContext:ctx];
}
@end
替代使用您想要的运行时
id cls = NSClassFromString(className);
id alloced_cls = objc_msgSend(cls, @selector(alloc));
id newEntity = objc_msgSend(alloced_cls, @selector(initWithEntity:insertIntoManagedObjectContext:), entity, ctx);
return newEntity;