0

編集:ここでのこの反対票シンドロームは、非常に時間がかかります。私は宿題をやったと思うところに質問をし、アドバイスを求めました。支持された回答は、コンパイル時の警告を使用することを暗示していましたが、私自身の、おそらく最もクリーンな OOP の方法には関心がありませんでした。

なぜこれが必要なのか、何をしようとしているのかを理解するための簡単な概要: データ マッパー パターンを実装する ORM を作成しています。マッパー (つまり、SQLite の結果用) は、基本エンティティ クラスの初期化子を使用して、エンティティ クラスのサブクラスを作成する必要があります。だから問題があります。

マッパーは、特定のクラスについて認識していませんし、認識すべきでもありません。さまざまなデータ ソースのマッピングの説明と特定のマッパーは、エンティティ クラスから抽象化されており、エンティティの説明の一部として設計されています。

エンティティは NSManagedObject に似ていますが、ORM は異なるパターンに従います。エンティティが作成される説明は、NSEntityDescription に似ています (ただし、異なるパターンと目的に従います)。

したがって、私の目標は、ManagedEntity の init メソッドを使用して、ManagedEntity のサブクラスであることがわかっているエンティティを作成することです。

したがって、マッパーの初期化は次のようになります。

- (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 の子クラスを作成するにはどうすればよいでしょうか。

もちろん、initWithEntityDescription に RespondsToSelector() を使用して呼び出すこともできます。しかし、クラスの種類が既にわかっている場合は、よりエレガントな方法があるはずだと何かが教えてくれます。また、 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 に答える