0

我正在尝试在 IOS 中编写一个带有块的完成处理程序,但不确定它为什么不工作。

这是我到目前为止所拥有的

typedef void(^myCompletion)(BOOL);

-(void) showAnswer {
   [self showAnswer:^(BOOL finished) {
       if (finished) {
         LnbScene *scene = (LnbScene *)gameScene.lnbScene;
         //once the tiles position have been updated then move to the next riddle
           [scene nextRiddle];
       }
   }];
}

// This method should update the position of tiles on the scene
    -(void) showAnswer:(myCompletion) compblock{
        LnbScene *scene = (LnbScene *)gameScene.lnbScene;
        NSArray *tilesArray = [scene.tilesBoundary children];

        for (Tile *tile in tilesArray) {
            if (tile.positionInAnswer != 17) {
                [tile removeFromParent];
                [scene.spacesBoundary addChild:tile];
                CGPoint targetPoint = CGPointMake(tile.targetPoint.x, tile.targetPoint.y + 6);
                tile.position = targetPoint;
            }
        }
        compblock(YES);
    }

我正在从场景中调用 showAnswer 方法,如下所示:

     GameViewController *gVC = (GameViewController *)self.window.rootViewController;
     [gVC showAnswer];

当我逐步执行代码时,我没有遇到任何错误,并且序列按预期进行,即。磁贴位置发生更改,然后完成处理程序触发到 nextRiddle 方法。唯一的问题是没有更新任何界面。有什么我想念的吗?

我已经通过取出完成块测试了磁贴重新定位的代码是否有效,我在界面中查看它并获得所需的结果。所以我很确定问题在于我如何实现这些块。我以前从来没有写过一个块,所以我真的一头雾水。

-(void) showAnswer {
    LnbScene *scene = (LnbScene *)gameScene.lnbScene;
    NSArray *tilesArray = [scene.tilesBoundary children];

    for (Tile *tile in tilesArray) {
        if (tile.positionInAnswer != 17) {
            [tile removeFromParent];
            [scene.spacesBoundary addChild:tile];
            CGPoint targetPoint = CGPointMake(tile.targetPoint.x, tile.targetPoint.y + 6);
            tile.position = targetPoint;
        }
    }
}
4

2 回答 2

1

我认为这个问题似乎是一个概念上的错误——-(void) showAnswer:(myCompletion) comp block方法中的代码“流”真实地表示了 UI 元素在表示层中的时间流。

然而在实践中,它并不是那么简单。UI 层以 60 Hz 帧速率呈现。这意味着您每秒可以看到 60 个(帧)屏幕,并且每个屏幕的内容都需要提前计算、处理、展平、渲染。

这意味着 1 帧(屏幕)循环/通过持续大约。16 毫秒。如果我没记错的话,作为一名程序员,你有 11 毫秒的时间来提供所有相关代码,以便将其处理成可视信息。这段代码被一次性处理,这就是我们问题的答案

想象一下,如果你有一个方法会说

{
   //some other UI code...
   self.view.backgroundColor = [UIColor greenColor]; 
   self.view.backgroundColor = [UIColor yellowColor]; 
   //some other UI code...
}

现在想象我们在 1 个这样的 16 毫秒通道内。这段代码将在任何渲染发生之前预先处理,结果背景颜色将为黄色。为什么?因为在循环准备阶段,此代码被处理并且框架将绿色解释为毫无意义,因为该值立即被黄色覆盖。因此,渲染器的指令将仅包含黄色背景信息。

现在回到你的实际代码。我认为你所有的代码都被处理得足够快,可以适应那个 11 毫秒的窗口,问题是你并没有真正等待瓷砖的交换,因为有一个带有 YES 参数的块作为方法的一部分,并且一个已经滑动无论接下来发生什么。

所以渲染的确实得到了简单地继续下一件事的指令。而且它没有动画。

尝试将此“瓷砖交换”放入“动画”块
[UIview animateWithDuration:....completion] 方法..并将您的块放入完成块中。是的,你会有一个街区,但那很好。

[UIView animateWithDuration:0.4f
                 animations:^{
                                 //tile swapping code
                            }
                 completion:^(BOOL finished)
                             {
                                 complBlock(YES);
                             }];

我不完全确定它是否会起作用,但让我们试试。

于 2015-03-02T01:03:03.513 回答
0

UI 相关方法应该在主线程上调用。你可以试试这个:

[self showAnswer:^(BOOL finished) {
   if (finished) {
     LnbScene *scene = (LnbScene *)gameScene.lnbScene;

     dispatch_async(dispatch_get_main_queue(), ^{
          [scene nextRiddle];
     });
   }
}];
于 2016-06-02T06:17:36.207 回答