1

我一直在重写我的模型层,以便在多个现有应用程序中使用。现有的代码库已经过时了,我想概括一下我的方法,以便将来更容易扩展,并获得最新语言/技术添加的好处(ARC 为其中之一)。

我的目标是一个可移植的、由 SQL 支持的“框架”,由一个简单的数据库层(建立在 FMDatabase 之上)和健壮的模型对象类组成,它们共同封装了大部分复杂性。模型对象是主超类的子类,并遵守合同来实现(和覆盖)方法,这些方法提供必要的属性和模式细节以促进 SQL 操作。

我在 PHP 中使用这种方法取得了很大的成功,但在使用 Objective-C 时遇到了问题。

是的,CoreData 提供了这些东西,但由于多种原因不是一种选择。我还看到了在运行时解决问题的解决方案,但我不确定这是否适用于 ARC,并且更愿意在编译之前生成访问器。

我从为多线程访问维护基于锁的模式与基于 GCD 的方法(这里提出的问题)的辩论开始,并最终得到以下模式:

- (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) 更加困难。我可以为列表中的每个属性传入扩展宏,但这个“节省时间”现在看起来完全相反——一长串元组并不比一个单独调用宏的列表更具可读性。

我希望我忽略了一些使这成为可能的东西,或者也许有人已经构建了一个我还没有找到的解决方案。也许是一个预处理脚本来生成包含访问器的类别......?我还没有研究过这个选项,但我可以接受,特别是如果它扩展到其他语言以实现跨平台定位。

建议表示赞赏。

4

1 回答 1

0

我最终编写了一个 Python 脚本,该脚本查看模型对象头文件中的属性声明,并在每个类的新类别中写出自定义访问器。为方便起见,我使用以下形式的注释字符串注释我的属性声明:

// SqlFieldName SqlFieldType

我已经为对象与原始访问器定义了几个基本模板。

结果是非常具体的实现,但为访问器节省了大量的复制/粘贴/查找/替换工作,由于在查找/替换期间重命名的疏忽,这通常是至少 1 个错误的来源。

使用类别来存储访问器会导致编译警告,以覆盖类别中的对象方法,但您可以使用 -Wobjc-protocol-method-implementation 使这些方法静音。

我生成的代码非常符合我的需求,但如果有人感兴趣,我会发布它。

于 2013-04-14T17:01:38.823 回答