【发布时间】:2013-04-12 05:15:23
【问题描述】:
我一直在重写我的模型层,以便在多个现有应用程序中使用。现有的代码库已经过时了,我想概括一下我的方法,以便将来更容易扩展,并从最近的语言/技术添加中受益(ARC 为其中之一)。
我的目标是一个可移植的、由 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"];
}
});
}
我喜欢它,但我希望能够生成属性列表以简化模型对象代码。我的第一步是创建宏扩展来构建访问器/修改器。不过,在这里我已经遇到了不太完美的选择。
1) 在宏中迭代列表是一个丑陋的过程。 Boost.preprocessor 可能是一种选择,但考虑到(2 和 3)它有点吓到我。
2) 需要在所用令牌的所有可能版本中传递宏(即,我必须传递 creationDate 和 CreationDate 只是为了满足生成上述示例的 getter 和 setter。)但也不理想。
3) 对象和原始类型需要不同的宏扩展,这使得遍历属性列表 (1) 更加困难。我可以为列表中的每个属性传入扩展宏,但这个“节省时间”现在看起来完全相反 - 长长的元组列表并不比单个调用宏的列表更具可读性。
我希望我忽略了一些使这成为可能的东西,或者也许有人已经构建了一个我还没有找到的解决方案。也许是一个预处理脚本来生成包含访问器的类别......?我还没有研究过这个选项,但我可以接受,特别是如果它扩展到其他语言以实现跨平台定位。
建议。
【问题讨论】:
-
我想知道您不使用核心数据的“原因数量”?核心数据非常棒,您不会自己编写更好的版本。
-
1) 您的架构必须进行逆向工程,因此很难跨平台共享。例如,我不知道任何可以保证更改范围有限的标准布局技术。 2) 将 CoreData 与 iCloud 一起使用存在问题(并不是说 iCloud 对我来说是一个真正的解决方案)——我需要提供一个跨平台同步层,并且希望能够在我认为最有意义的地方插入它。 3) 过去,我一直被 CoreData 的错误所困扰,这些错误诊断起来非常耗时。这些是我舌尖上的那些。 #1 对我来说很重要。
-
我想跨平台是一个很好的理由!
标签: objective-c multithreading model macros grand-central-dispatch