【问题标题】:Objective-C accessor templateObjective-C 访问器模板
【发布时间】: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


【解决方案1】:

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

// SqlFieldName SqlFieldType

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

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

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

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

【讨论】:

    猜你喜欢
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-20
    • 2011-12-30
    • 1970-01-01
    相关资源
    最近更新 更多