我是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:..
答案 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 class,categories,delegation,notification等。)