4

我有一个Objective C中的异步方法,你传递一个完成处理程序。是否有可能避免写这个块调用代码'倒退'?

我希望有条件地在两个不同的对象上运行这个方法两次,然后处理结果。

我可以找到做这项工作的唯一方法就是按照下面的方式写代码'向后'。

这意味着我的主要架构失败。有没有更好的办法?

defines.h

#define BLOCK_SAFE_RUN(block, ...) block ? block(__VA_ARGS__) : nil 

myController.h

// Code executes in the order (0),(1),(2),(3),(4) - see comments 


    // (0) Create the origin completion handler 
    void (^originCompletionHandler)(FAPlacePoint *, BOOL, BOOL) = ^void (FAPlacePoint *savedOriginPP, BOOL geoCodeDidSucceed, BOOL saveDidSucceed) 
    { 

     // (2) Create the destination completion handler 
     void (^destinationCompletionHandler)(FAPlacePoint *, BOOL, BOOL) = ^void (FAPlacePoint *savedDestinationPP, BOOL geoCodeDidSucceed, BOOL saveDidSucceed) 
     { 

      // (4) 
      // Everything is finished. Do something with savedOriginPP and savedDestinationPP 


     }; 

     // (3) Conditionally run the geocode method with the dest point then call the destination completion handler 
     if (destinationPlacePoint.currentLocation) 
      [self reverseGeocodeThenSavePlacePoint:destinationPlacePoint completion:destinationCompletionHandler]; 
     else 
     { 
      FAPlacePoint * pp = [self storePlacePoint:destinationPlacePoint]; 
      BLOCK_SAFE_RUN(destinationCompletionHandler, pp, YES, YES); 
     } 


    }; 


    // (1) Conditionally run the geocode method with the origin point then call the origin completion handler 
    if (originPlacePoint.currentLocation) 
     [self reverseGeocodeThenSavePlacePoint:originPlacePoint completion:originCompletionHandler]; 
    else 
    { 
     FAPlacePoint * pp = [self storePlacePoint:originPlacePoint]; 
     BLOCK_SAFE_RUN(originCompletionHandler, pp, YES, YES); 
    } 

回答

2

你有重复的代码,所以应该分离到的方法:

- (void) processPoint:(FAPlacePoint*)point completionHandler:(void (^)(FAPlacePoint *savedPP, BOOL geoCodeDidSucceed, BOOL saveDidSucceed))completionHandler 
{ 
    if (point.currentLocation) 
     [self reverseGeocodeThenSavePlacePoint:point completion:completionHandler]; 
    else 
    { 
     FAPlacePoint * pp = [self storePlacePoint:point]; 
     BLOCK_SAFE_RUN(completionHandler, pp, YES, YES); 
    } 
} 

这可以让你避免存储在变量块只是为了避免重复它们。所以,你的代码减少到:

[self processPoint:originPlacePoint completionHandler:^void (FAPlacePoint *savedOriginPP, BOOL geoCodeDidSucceed, BOOL saveDidSucceed) { 
    [self processPoint:destinationPlacePoint completionHandler:^void (FAPlacePoint *savedDestinationPP, BOOL geoCodeDidSucceed, BOOL saveDidSucceed) { 

     // Everything is finished. Do something with savedOriginPP and savedDestinationPP 

    }]; 
}]; 
3

这意味着在我的部分主要的建筑失败。有没有更好的办法?

不,它不。也许你只需要调整你的观点。

在定义它之前,您不能使用变量来调用块,因此类似完成处理程序的代码将始终位于调用它的代码之前。这没什么错。这就像在执行之前告诉别人你的计划:离开办公室后,我会在杂货店停下来。计算机语言通常不会有实际的将来时态,但它可能有助于在将它们称为未来时编写代码之前定义块。

如果真的困扰你有导致它运行的代码之前完成代码,有时你可以把这些代码在其自己的方法,这样完成块本身是由多一点打电话到该方法。当然,该方法可以跟随调用它的代码(但在使用完成块本身之前仍需要定义它)。

+0

我不知道你有什么想法,你必须在使用它之前定义一个块。任何采用block参数的方法都可以使用与调用内联的块进行定义。所以要运行一系列的程序段才能嵌套。 – 2014-12-04 21:44:51

+0

@jshier更确切地说,你必须定义一个block *变量*,然后才能使用它来调用该块。当然,你可以使用块本身作为参数,但是你会注意到OP想要从两个不同的地方调用同一个块。 Ken Thomases的回答有助于避免在这种特殊情况下的需要。但是,一般来说,如果要在多个地方使用同一个块,则需要将其分配给一个变量,而在使用该变量调用块之前,您显然需要这样做。 – Caleb 2014-12-04 22:26:26

+0

我非常感谢你的回答。我给予Ken Thomases的答案的唯一原因是,严格地说,他提供了解决所述问题的代码。 – 2014-12-17 17:07:49

相关问题