我一直在努力重写我的模型层,以便在几个现有应用中使用。现有的代码库已经过时了,我想概括一下我的方法,以便在将来更容易扩展,并获得最新语言/技术添加的好处(ARC for one)。
我的目标是一个可移植的,由SQL支持的“框架”,由一个简单的数据库层(构建在FMDatabase之上)和强大的模型对象类组成,它们共同封装了大部分复杂性。模型对象从主超类中继承子类并遵守合同来实现(和覆盖)方法,这些方法提供必要的属性和模式细节以促进SQL操作。
我在PHP中使用这种方法取得了很大的成功但是遇到了Objective-C的问题。
是的,CoreData提供了这些东西,但出于多种原因不是一种选择。我也看到了在运行时解决问题的解决方案,但我不确定它是否适用于ARC,并且更愿意在编译之前生成访问器。
我开始讨论维护基于锁定的多线程访问模式与基于GCD的方法(question raised here)的争论,并最终采用以下模式:
- (NSDate *)creationDate {
__block NSDate *aDate;
dispatch_sync(accessorQueue, ^{
aDate = creationDate;
});
return aDate;
}
- (void)setCreationDate:(NSDate *)aDate {
if (![aDate isKindOfClass: [NSDate class]]) {
NSLog(@"setCreationDate: called with non-date object);
return;
}
dispatch_barrier_async(accessorQueue, ^{
if ((!creationDate && aDate) || ![aDate isEqualToDate: creationDate]) {
[self willChangeValueForKey: @"creationDate"];
[changes setObject: aDate ? aDate : [NSNull null]
forKey: @"creationDate"];
creationDate = aDate;
[self didChangeValueForKey: @"creationDate"];
}
});
}
我喜欢它,但我希望能够生成一个属性列表来简化模型对象代码。我的第一步是创建宏扩展来构建访问器/ mutator。在这里,我已经遇到了不太完美的选择。
1)迭代宏中的列表是一个丑陋的过程。 Boost.preprocessor可能是一个选项,但考虑到(2& 3)它让我害怕。
2)宏需要在所使用的令牌的所有可能版本中传递(即,我必须传递creationDate和CreationDate,以满足上面示例的生成getter和setter。)不是show-stopper但也不理想。
3)对象和基元类型需要不同的宏扩展,这使得迭代属性列表(1)变得更加困难。我可以为列表中的每个属性传递扩展宏,但是这个“节省时间”现在看起来完全相反 - 一个长元组列表的可读性远不如单个宏调用列表。
我希望我忽略了使这成为可能的事情,或者有人已经建立了一个我没有找到的解决方案。也许是一个预处理脚本来生成包含访问器的类别......?我还没有考虑过这个选项,但是可以使用它,特别是如果它扩展到其他语言以进行跨平台定位。
建议表示赞赏。
答案 0 :(得分:0)
我最终编写了一个Python脚本,该脚本查看模型对象头文件中的属性声明,并为每个类在新类别中写出自定义访问器。为了方便起见,我使用以下形式的注释字符串注释我的属性声明:
// SqlFieldName SqlFieldType
我已经为对象和原始访问器定义了几个基本模板。
结果是特定于实现的,但是为访问者节省了大量的复制/粘贴/查找/替换工作,这通常是由于在查找/替换期间重命名的疏忽导致至少1个错误的来源。
使用类别来存储访问器会导致编辑警告以覆盖类别中的对象方法,但是您可以使用-Wobjc-protocol-method-implementation来静音。
我生成的代码非常符合我的需求,但如果有人有兴趣,我会发布它。