0

编辑:这里的这种投票综合症很糟糕。我问了一个问题,我认为我做了功课,并征求意见。赞成的答案暗示了编译时警告,而我自己的,可能是最干净的 OOP 方式没有引起任何兴趣。

简要概述以了解我为什么需要它以及我尝试做什么:我正在编写一个实现数据映射器模式的 ORM。映射器(即用于 SQLite 结果)必须创建实体类的子类 - 使用基实体类的初始化程序。所以有问题。

映射器不知道也不应该知道特定的类。不同数据源的映射描述和特定映射器从实体类中抽象出来,并且是实体描述的设计部分。

实体类似于 NSManagedObject,尽管 ORM 遵循不同的模式。创建任何实体的描述类似于 NSEntityDescription(但也遵循不同的模式和目的)。

所以我的目标是使用 ManagedEntity 的 init 方法创建我知道是 ManagedEntity 子类的实体。

所以我的映射器的 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 和选择器调用将只进行运行时检查。即使实体初始化程序不应该改变,如果这个方法存在,失去编译时间检查似乎是一个糟糕的选择。

4

2 回答 2

5

作为映射的一部分,您必须知道您需要什么子类。然后使用

ManagedEntity *newEntity = [[NSClassFromString(className) alloc] initWithEntityDescription:_entityDescription];

编辑:按照我的承诺,我正在一个 GitHub 项目中构建它,并意识到为什么它可能无法编译。您必须-initWithEntityDescription:在范围内可访问的已知类中声明。在这种情况下,这意味着您必须声明和实施ManagedEntity -initWithEntityDescription:,并且在文件顶部有 `#import "ManagedEntity.h"。

于 2013-10-20T12:44:55.537 回答
0

为了加强尼尔的正确答案,即 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;
于 2013-10-20T16:15:42.470 回答