完成块目标-C

时间:2015-03-02 00:27:18

标签: objective-c objective-c-blocks completionhandler

我正在尝试用IOS在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方法。唯一的问题是没有任何接口被更新。有什么我想念的吗?

我已经通过取出完成块测试了tile重新定位的代码,我在界面中查看它并获得所需的结果。所以我很确定问题在于我是如何实现这些块的。我以前从未写过一个块,所以我真的在黑暗中。

-(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;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

我认为问题似乎是一个概念上的错误 - " flow"代码 在-(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:....完成]方法..并将您的块放入完成块。是的,你会在一个区块中有一个区块,但没关系。

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

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

答案 1 :(得分:0)

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

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

     dispatch_async(dispatch_get_main_queue(), ^{
          [scene nextRiddle];
     });
   }
}];