【问题标题】:Getting the min/max coordinates of NSValue transformed CGPoints in an NSArray using KVC使用 KVC 在 NSArray 中获取 NSValue 转换的 CGPoints 的最小/最大坐标
【发布时间】:2013-05-23 04:46:16
【问题描述】:

我最近阅读了一些关于Key-Value Coding 的文档和一些博客文章,发现它非常有用。我想将它用于我的案例,但到目前为止我还没有成功。

就我而言,我有一个包含CGPointNSMutableArray 已转换为NSValue。我将向该数据数组添加许多点,并且我想获得最小/最大 x 和 y 值。例如:

NSMutableArray *data = [[NSMutableArray alloc] init];
[data addObject:[NSValue valueWithCGPoint:CGPointMake(20.0f, 10.0f)]];
[data addObject:[NSValue valueWithCGPoint:CGPointMake(5.0f, -15.0f)]];
[data addObject:[NSValue valueWithCGPoint:CGPointMake(-5.0f, 20.0f)]];
[data addObject:[NSValue valueWithCGPoint:CGPointMake(15.0f, 30.0f)]];

// min X:  -5.0,  max X: 20.0
// min Y: -15.0,  max Y: 30.0

到目前为止,我有两种方法。第一个是将这四个值存储在类实例变量中,当添加新对象时,将其与这些变量进行比较,并在必要时更新它们。第二种方法涉及到一个 for 循环来找到极值,但是这种方法效率低。

如果可能的话,我想使用 KVC 来完成这项任务,我相信这将是一个比我拥有的更通用的解决方案。将来,我可能还需要从数组中删除一些对象,这会使我的第一种方法不适用,剩下的就是 for 循环。

我尝试使用一些关键路径,即@"@max.x"@"@max.position.x",但我得到的只是NSUnknownKeyException

【问题讨论】:

  • 这些关键路径从何而来?无论如何,如果您保持数组排序,那么您将有更好的时间(并且您也不需要 for 循环)。您可以通过分而治之的方式插入(从中间开始,根据值的高低选择中途,每 100 个值最多只能尝试 7 次)。
  • @borrrden,我无法对数组进行排序,因为这些数据用于绘图目的。我从documentation:CGPoint Key Paths If the value of a given property is a CGPoint data type, you can append one of the field names in Table C-3 to the property to get or set that value. For example, to change the x component of a layer’s position property, you could write to the key path position.x.得到了keyPaths
  • 我的意思是“最大”的东西。那是什么?
  • @tolgamorf:如果你访问CALayer的a的key path就可以了,但不是一般的NSValue,比较stackoverflow.com/a/15657943/1187415
  • @borrrden 这个blog entry 对可以在关键路径中使用的简单集合运算符有很好的解释。

标签: ios objective-c kvc


【解决方案1】:

如果您使用类别告诉NSValue 如何访问CGPointxy 值,您可以使其工作:

@interface NSValue (MyKeyCategory)
- (id)valueForKey:(NSString *)key;
@end

@implementation NSValue (MyKeyCategory)
- (id)valueForKey:(NSString *)key
{
    if (strcmp([self objCType], @encode(CGPoint)) == 0) {
        CGPoint p = [self CGPointValue];
        if ([key isEqualToString:@"x"]) {
            return @(p.x);
        } else if ([key isEqualToString:@"y"]) {
            return @(p.y);
        }
    }
    return [super valueForKey:key];
}
@end

然后

CGFloat maxx = [[yourArray valueForKeyPath:@"@max.x"] floatValue];

确实有效。但请注意,一个简单的循环会快得多,特别是如果您必须计算所有 4 个值 @max.x@max.y@min.x@min.y

【讨论】:

    【解决方案2】:

    这在您当前的方法中是不可能的。 CGPoint 不是 obj-c 对象,因此您无法通过 KVC 探索它的值。 NSValue 仅将 CGPoint 视为二进制数据,不了解数据的内部结构。编译后甚至无法访问 CGPoint 字段的名称 xy

    CGPoint 值可以被 KVC 访问的唯一例外是 CAAnimationCALayer,它们会覆盖键值搜索)。

    可能最好的解决方案是自己实现它,注意你可以做一些巧妙的缓存——添加点时测试当前的最大值/最小值,删除当前的最小值/最大值时清除最小值/最大值。

    【讨论】:

    • 您是建议创建自定义 keyPath 还是基于我的方法的实现?
    • @tolgamorf 我建议完全离开 KVC 并将数组和最小/最大搜索包装到一个特殊的类中。
    猜你喜欢
    • 2013-02-15
    • 1970-01-01
    • 1970-01-01
    • 2013-08-16
    • 1970-01-01
    • 1970-01-01
    • 2017-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多