Objective c 避免嵌套KVO键路径中硬编码字符串的最佳方法

Objective c 避免嵌套KVO键路径中硬编码字符串的最佳方法,objective-c,key-value-observing,Objective C,Key Value Observing,当通过KVO注册观察对象时,我编写此代码以避免硬编码字符串: [myObject addObserver:self forKeyPath:NSStringFromSelector(@selector(myProperty)) options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL]; 请注意NSStrin

当通过KVO注册观察对象时,我编写此代码以避免硬编码字符串:

[myObject addObserver:self
           forKeyPath:NSStringFromSelector(@selector(myProperty))
              options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
              context:NULL];
请注意NSStringFromSelector。它在编译时保护我,以防我更改了myProperty的名称而忘记了观察它的内容

但使用嵌套属性时,情况更为复杂,例如“myProperty1.myProperty2”

我的简单解决方案是使用如下宏:

#define KEYPATHSTRING1(a) NSStringFromSelector(@selector(a))
#define KEYPATHSTRING2(a, b) [NSString stringWithFormat:@"%@.%@", NSStringFromSelector(@selector(a)), NSStringFromSelector(@selector(b))]
#define KEYPATHSTRING3(a, b, c) [NSString stringWithFormat:@"%@.%@.%@", NSStringFromSelector(@selector(a)), NSStringFromSelector(@selector(b)), NSStringFromSelector(@selector(c))]
有更好的或标准化的解决方案吗?在谷歌上的搜索结果并没有为我找到解决这个问题的答案。

我还没有尝试过(甚至没有编译过),但你可以使用可变辅助方法:

+ (NSString *)keyPathFromSelectors:(SEL)firstArg, ...
{
    NSMutableArray *keys = [NSMutableArray array];

    va_list args;
    va_start(args, firstArg);

    for (SEL arg = firstArg; arg != nil; arg = va_arg(args, SEL))
    {
        [keys addObject:NSStringFromSelector(arg)];
    }

    va_end(args);

    return [keys componentsJoinedByString:@"."];
}

我使用libexobjc中的EXTKeyPathCoding.h。您可以在

Swift 3中检查它们是如何从“属性链”生成密钥路径字符串的


函数中的标记不是字符串,编译器将对其进行检查。

我理解您的观点,但觉得我的问题的范围定义得很好,足以证明发布此问题是正确的。我可以将“更好”定义为客观的——正确的、完整的、自动可扩展的(也就是说,不要为每个变量数写一行)——但我认为这些客观的考虑对任何读者来说都是显而易见的。此外,我找不到任何资源,我认为是一个有效的研究课题。对于违反任何规则或惯例表示歉意。在我看来,这种情况可能非常普遍,我认为有人已经优雅地解决了它。显然情况并非如此。因此,是的,另一个同意没有更优雅的解决方案的想法会有所帮助。或者,如果有人是预处理器宏的向导,他能将我笨拙的解决方案浓缩成一行代码,处理任意数量的变量,那么他也会很受欢迎。我不喜欢这种个人挖苦。巴德,我不是来拍拍你的背的。如果你想让我删除这个问题,就告诉我。我不想假装是个专家。但我真的觉得这是一个有效的、未回答的问题,属于知识库。哦,非常有趣,非常感谢。我会尝试一下,让你知道我的想法。我认为这比我的解决方案好,原因有二。(1) 它避免了预处理器宏,我通常喜欢这样做,因为宏会掩盖实际编译的代码;(2)它处理任意数量的参数。如果它真的有效,那就太好了。所以我真的很喜欢这种方法,但我遇到了一个问题,我对变量args不太了解。我运行该方法三次,第一次使用一个变量(选择器),然后使用三个变量,而不是第一次使用同一个变量。前两个有效,第二个崩溃,崩溃时for循环中arg的值是某种垃圾/坏内存地址/等。引发的异常无法将nil插入keys数组。您是否使用nil终止参数?让我继续并使用facepalm,同时重申“我不熟悉变量args”哈哈。我会试试这个,但我很肯定它会奏效的。:)非常感谢,我会在确认后接受这是我的首选答案。哦,对不起,我忘了提及。在你的回答中,返回类型应该是“NSString*”而不是“NSString”--我不能提交编辑,因为这么说编辑必须至少包含6个字符。我非常感谢这个答案,这正是我所期待的,但我正在等待Wain对我的评论的回复,因为我更希望尽可能避免使用宏。
let keyPathString = #keyPath(MyType.myProperty1.myProperty2)