使用另一个 class 的选择器以编程方式构建 属性 路径。这是如何运作的?

Bulding property paths programatically with another class's selectors. How does this work?

我有一个方法 I,它采用可变数量的 @selector() 值和 returns 我不久前在此站点上找到的正确 NSString。这在为我构建 属性 路径时很有用,因为我不喜欢为此使用字符串的想法,并且喜欢编译器能够检查构建路径的值的想法。方法是:

+(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:@"."];
}

效果很好,但问题是:为什么?如果我在名为 person 的当前对象上有 属性 并且它有一个 name 路径显然是 person.name 并且对我的方法的调用看起来像:

+(NSSet *)keyPathsForValuesAffectingFoo
{
    return [NSSet setWithObject:[self keyPathFromSelectors:@selector(person), @selector(name),nil]];
}

name 选择器在技术上(不应该)在我当前的 class 中可见,它在我有参考的 Person class 中,所以如何我访问了正确的 name SEL 对象?

选择器不保证该方法实际存在于相关对象上。您可能会收到编译器警告,指出选择器名称在任何地方都不存在,但您无法保证它确实存在于将要使用的对象上。例如,这个编译:

[person performSelector: @selector(applicationDidBecomeActive:)]

即使 applicationDidBecomeActive 存在于您的应用委托中而不是 person

但是!这种事情可以通过编译器宏实现的。查看 libextobjc 库,它提供了您正在寻找的那种 selector/key 路径编译时检查。这就是 ReactiveCocoa 中许多关键路径魔法的强大动力,但它也可以独立使用。