【问题标题】:Am I using Objective-C collections properly here?我在这里正确使用了 Objective-C 集合吗?
【发布时间】:2010-10-29 00:25:22
【问题描述】:

我正在尝试编写一个 iPhone 游戏。此功能旨在将重力施加到多个物体上。我从 Python 移植它,我想知道我将字典和数组用作元组是否有意义,并且在 Objective C 中是典型/惯用的。代码中的任何 cmets 都表示赞赏。

+ (void)updateBodies:(NSMutableArray*)bodies {
    NSMutableDictionary* totals = [NSMutableDictionary dictionaryWithCapacity:[bodies count]];
    for (Body* body in bodies) {
        if (body.fixed) {
            continue;
        }
        float tx;
        float ty;
        for (Body* other in bodies) {
            if (other == body) {
                continue;
            }
            float dx = other.x - body.x;
            float dy = other.y - body.y;
            float dist2 = pow(dx, 2) + pow(dy, 2);
            float dist = sqrt(dist2);
            float mass = pow(other.radius, 3);
            float magnitude = G * mass / dist2;
            float ux = dx / dist;
            float uy = dy / dist;
            tx += ux * magnitude;
            ty += uy * magnitude;
        }
        NSNumber* ntx = [NSNumber numberWithFloat:tx];
        NSNumber* nty = [NSNumber numberWithFloat:ty];
        NSArray* tuple = [NSArray arrayWithObjects:ntx, nty, nil];
        [totals setObject:tuple forKey:body];
    }
    for (Body* body in [totals allKeys]) {
        NSArray* tuple = [totals objectForKey:body];
        float tx = [[tuple objectAtIndex:0] floatValue];
        float ty = [[tuple objectAtIndex:1] floatValue];
        body.dx += tx;
        body.dy += ty;
    }
}

【问题讨论】:

  • 我刚刚意识到我可以在第一个循环中更新dxdy。出于某种原因,我认为我必须延迟更新它们,如果我更新xy,这将是正确的。所以现在这会变得更简单,但它仍然是 NS 集合的好习惯。
  • for (Body* body in [totals allKeys]) 可以写成for (Body* body in totals)

标签: objective-c coding-style


【解决方案1】:

您应该注意的唯一问题是NSDictionary 复制了它的密钥。所以Body需要实现NSCopying,而totalsBody的实例不一定与传入的bodies数组中的实例相同,具体取决于您实现NSCopying的方式。

我将使用的方法是将速度视为身体的一种属性。这样你就不需要字典来将 body 与它的速度相关联,你可以遍历数组本身。


谈到迭代。您可以通过在计算第一个物体的同时计算另一个物体的速度来将迭代次数和一些计算减半。即您的内部循环只会遍历数组中外部循环主体之后的主体。

这意味着您不能使用快速迭代,因此您必须分析以确定哪种方法更快。


我觉得有点小意思

 for ....
 {
     if (!condition)
     {
         continue;
     }
     // do stuff
 }

真的很丑。有什么问题:

 for ....
 {
     if (condition)
     {
         // do stuff
     }
 }

【讨论】:

  • continue 方法减少了嵌套。就像函数中的提前返回一样。
  • 谢谢,我最终发现了NSCopying 问题。我改用 NSMutableArray 而不是 NSMutableDictionary。
  • @FogleBird:它不会减少嵌套,它只是伪装它。
  • @JeremyP:你对嵌套的定义是什么?这就是// do stuff 是一个缩进还是两个缩进的区别。
  • @FogleBird:源代码的缩进应该反映它的结构。我的两个示例的结构实际上是相同的,因为我们有一个嵌套在循环中的有条件执行的语句序列(do stuff 部分),但在第二个例子中,缩进正确地反映了结构。
【解决方案2】:

您可以使用块枚举进行最终更新:

[totals enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  Body* body = key;
  NSArray* tuple = key;
  body.dx += [[tuple objectAtIndex:0] floatValue];
  body.dy += [[tuple objectAtIndex:1] floatValue];
}];

另一种解决方案可能是不使用 NSDictionary 和 NSArray 并使用 C 数组。它应该比使用(和创建)对象更快。

【讨论】:

  • 他已经在使用快速枚举了。这就是for(... in ...)
  • 是的...我犯了一个错误。我会说块枚举没有调用 -allKeys 然后 objectForKey 应该比块昂贵
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多