【问题标题】:How can I access non-KVC compliant properties with just their name?如何仅使用其名称访问不符合 KVC 的属性?
【发布时间】:2014-03-01 02:46:57
【问题描述】:

上下文:我在一个自定义类中有几个 CGPathRef,从 NSObject 派生,命名为 model。我正在寻找一种方法来返回特定的 CGPathRef,基于我在运行时生成的字符串。

简化示例,如果我可以使用 KVC:

#model.h
@property (nonatomic) CGMutablePathRef pathForwardTo1;
@property (nonatomic) CGMutablePathRef pathForwardTo2;
@property (nonatomic) CGMutablePathRef pathForwardTo3;
...


#someVC.m
-(void)animateFromOrigin:(int)origin toDestination:(int)destination{
    int difference = abs(origin - destination);
        for (int x =1; x<difference; x++) {
            NSString *pathName = [NSString stringWithFormat:@"pathForwardTo%d", x];
            id cgPathRefFromString = [self.model valueForKey:pathName];
            CGPathAddPath(animationPath, NULL, cgPathRefFromString);
        }
}

问题:我怎样才能访问不符合 KVC 的属性 (CGPathRef),只将其名称表示为字符串?

【问题讨论】:

  • 您将它们称为“属性”。他们有访问器方法吗?
  • 是的,希望我的编辑澄清了一点。谢谢
  • 当然您可以使用performSelector 类型操作来调用getter 方法,但目前尚不清楚如何获取该结果类型。您可能必须使用 methodForSelector 然后调用“原始”方法实现,这是我从未尝试过的。
  • 为什么它们不符合 KVC?声明的 @properties 默认符合 KVC。
  • @AndrewMadsen - 返回值不是对象或标量。

标签: objective-c cgpath kvc


【解决方案1】:

我会做(并且有时会做)是将 CGPathRef 完全包装在 UIBezierPath 中,以便它一个对象并具有由此产生的所有好处,包括 KVC,能够将其粘贴在NSArray 或 NSDictionary,以及 ARC 内存管理。毕竟,这正是 UIBezierPath (或多或少)。

【讨论】:

  • 还应注意,Apple 专门recommends 使用 UIBezierPath 来创建 路径以支持 CGPath,除非您确实需要 UIBezierPath 未公开的某些 CoreGraphics 功能。
【解决方案2】:

您应该能够为此使用 NSInvocation。比如:

// Assuming you really need to use a string at runtime. Otherwise, hardcode the selector using @selector()
SEL selector = NSSelectorFromString(@"pathForwardTo1");
NSMethodSignature *signature = [test methodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:selector];
[invocation setTarget:test];
[invocation invoke];

CGMutablePathRef result = NULL;
[invocation getReturnValue:&result];

您也可以直接使用正确的 objc_msgSend 变体来执行此操作,但 NSInvocation 更容易(尽管可能慢得多)。

编辑:我放了一个简单的小测试程序here

【讨论】:

  • 慢了数百倍。但这通常不是大问题。这仍然是一个非常有用的答案。
【解决方案3】:

这在cocoa-dev 上进行了详细讨论。简短的回答是:你不能直接。

但事实证明,有很多方法可以解决这个问题。在您的具体示例中,您应该将它们存储在一个数组中,然后您甚至不需要 KVC 调用。

同样,对于您的具体示例,另一种可能的解决方案是切换到UIBezierPath,可以根据需要与CGPath 相互转换。

作为一种更通用的解决方案,您可以将它们包装到一个只为您保存价值的对象中,并在那个上使用 KVC。这基本上就是NSValue 经常用于包装原始指针的方式。

完全通用的解决方案是你可以实现valueForUndefinedKey:,检查密钥,然后返回你想要的。例如,您可以将路径粘贴在数组中并根据给定的键对其进行索引。或者您可以将它们放在字典中并在那里查找(这基本上是CALayer 所做的)。当然,如果你真的需要它是动态的,你可以对运行时进行内省并基本上重新实现 KVC……这将是非常罕见的正确答案。几乎所有这些“通用”解决方案对于大多数问题来说都是多余的。

简短的回答是,KVC 并不总是能很好地处理非免费桥接的低级对象。

【讨论】:

    猜你喜欢
    • 2017-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多