ObjC:Class的Alloc实例和执行选择器导致__CFRequireConcreteImplementation

时间:2010-05-18 08:28:37

标签: iphone objective-c

我是Objective-C的新手,我想使用这样的模型类来抽象我的数据库访问:


@interface LectureModel : NSMutableDictionary
{
}

-(NSString*)title;
-(NSDate*)begin;

...

@end

我使用字典方法setValue:forKey:来存储属性并将它们返回到getter中。现在我想通过动态使用Class从sqlite数据库中读取这些模型。


+ (NSArray*)findBySQL:(NSString*)sql intoModelClass:(Class)modelClass
{
  NSMutableArray* models = [[[NSMutableArray alloc] init] autorelease];

  sqlite3* db = sqlite3_open(...);

  sqlite3_stmt* result = NULL;
  sqlite3_prepare_v2(db, [sql UTF8String], -1, &result, NULL);

  while(sqlite3_step(result) == SQLITE_ROW)
  {
    id modelInstance = [[modelClass alloc] init];

    for (int i = 0; i < sqlite3_column_count(result); ++i)
    {
      NSString* key = [NSString stringWithUTF8String:sqlite3_column_name(result, i)];
      NSString* value = [NSString stringWithUTF8String:(const char*)sqlite3_column_text(result, i)];

      if([modelInstance respondsToSelector:@selector(setValue:forKey:)])
        [modelInstance setValue:value forKey:key];
    }

    [models addObject:modelInstance]; 
  }
  sqlite3_finalize(result);
  sqlite3_close(db);

  return models;
}

有趣的是,respondsToSelector:有效,但是如果我尝试(在调试器中)跳过[modelInstance setValue:value forKey:key],它将抛出一个异常,并且堆栈跟踪看起来像:

#0  0x302ac924 in ___TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION___
#1  0x991d9509 in objc_exception_throw
#2  0x302d6e4d in __CFRequireConcreteImplementation
#3  0x00024d92 in +[DBManager findBySQL:intoModelClass:] at DBManager.m:114
#4  0x0001ea86 in -[FavoritesViewController initializeTableData:] at FavoritesViewController.m:423
#5  0x0001ee41 in -[FavoritesViewController initializeTableData] at FavoritesViewController.m:540
#6  0x305359da in __NSFireDelayedPerform
#7  0x302454a0 in CFRunLoopRunSpecific
#8  0x30244628 in CFRunLoopRunInMode
#9  0x32044c31 in GSEventRunModal
#10 0x32044cf6 in GSEventRun
#11 0x309021ee in UIApplicationMain
#12 0x00002988 in main at main.m:14

那么,这有什么问题?据推测,我正在做一些非常愚蠢的事情,只是看不到它......

非常感谢你的回答,
Arakyd:..

2 个答案:

答案 0 :(得分:1)

我认为你需要从头开始重新审视Objective C,而不是C ++

你的代码示例没有告诉我们modelClass是一个LectureModel所以有些东西不见了所以我可能误解了一些东西。

首先你必须直接打电话给[super init] Apple Objective C Primer

在Objective C中,您使用的是组合而不是继承,而不是在C ++中 - 在此示例中,我将使用委托来允许使用字典。 LectureModel会将它不理解的任何消息传递给字典属性。同样来自NSDictionary NSDictionary和NSMutableDictionary是类集群的一部分,因此使用此接口创建的对象不是这两个类的实际实例。相反,实例属于其私有子类之一。

所以NSMutableDictionary并不是一个很好的扩展类。

这是部分代码,缺少许多部分,包括dealloc

@interface LectureModel : NSObject
{
  NSMutableDictionary *dict;
}

...

@end



@implementation LectureModel


-(LectureModel*)init
{
  if (self = [super init]) {
    dict = [[NSMutableDictionary dictionary]retain]; // need to keep this
  }
  return self;
}

- (void)forwardInvocation:(NSInvocation *)invocation   // See NSObject for details
{
    SEL aSelector = [invocation selector];

    [invocation invokeWithTarget:dict];   // let dict do the work
}

...
@end

答案 1 :(得分:1)

您是否尝试将NSMutableDictionary子类化?有一个博客条目!

http://cocoawithlove.com/2008/12/ordereddictionary-subclassing-cocoa.html

第一点建议?

  

最佳实践:不要继承

他是对的。试图将一个不设计为Cocoa子类的子类子类化通常比你想象的要难,并且99%的时间都不是必需的。


查看您发布的代码,看起来您不需要继承子类。创建一个实现标题的类并开始方法并使用字典来处理底层存储。

edit2:澄清了关于子类化的最后一句话。 Cocoa中的一些类被设计为子类(UIViewController,NSObject),并且愿意这样做,其他类不是设计为子类,并且需要大量仔细编码(在某些情况下,内部知识对象如何工作)才能获得它们工作正常。结论:除非你是为其设计的一个类的子类,否则要小心并考虑其他选择(decorator classcategoriesdelegationnotification等。)