在objective-c中避免使用异步代码嵌套块

时间:2014-08-10 12:37:22

标签: ios objective-c asynchronous objective-c-blocks

我需要在Objective-C代码中发生一系列很多事件。假设我有6件事 - thingA,thingB,thingC,thingD,thingE和thingF。 thingB和thingD返回BOOL。如果thingB为NO,那么thingC不需要被调用。如果thingD为NO,那么thingE不需要被调用。

- (void)doThings:(void(^)())completion {
    [self thingA: ^{
        [self thingB: ^(BOOL success) {
            if (success) {
                [self thingC: ^{
                    [self thingD: ^(BOOL success) {
                        if (thingD) {
                            [self thingE: ^{
                                [self thingF];
                                completion();
                            }];
                            return;
                        }

                        [self thingF];
                        completion();
                    }];
                }];
                return;
            }

            [self thingD: ^(BOOL success) {
                if (success) {
                    [self thingE: ^{
                        [self thingF];
                        completion();
                    }];
                    return;
                }

                [self thingF];
                completion();
            }];
        }];
    }];
}

这很快就会变得笨拙。你可以把那些有不同结果的东西带回到循环中,并将它们变成新的方法,如下:

- (void)doThings:(void(^)())completion {
    [self thingA: ^{
        [self attemptThingB: ^{
            [self attemptThingD: ^{
                [self thingF];
                completion();
            }]
        }];
    }]
}

- (void)attemptThingB:(void(^)())completion {
    [self thingB: ^(BOOL success) {
        if (success) {
            [self thingC: {
                completion();
            }];
            return;
        }

        completion();
    }];
}

- (void)attemptThingD:(void(^)())completion {
    [self thingD: ^(BOOL success) {
        if (success) {
            [self thingE: ^{
                completion();
            }];
            return;
        }

        completion();
    }];
}

这减少了代码重复,但仍然很混乱,难以跟踪。它甚至会导致名称笨拙的方法,这实际上只是这种特殊情况的辅助方法。

必须有更好的方法。看起来很像同步编码的东西,但是是异步的。上面的代码很难阅读,如果我想在流程中添加一些新内容,就会很危险。

建议更好的解决方案?像这样的东西?

- (void)doThings {
    [self thingA];
    BOOL thingBSuccess = [self thingB];
    if (thingBSuccess == YES) {
        [self thingC];
    }
    BOOL thingDSuccess = [self thingD];
    if (thingDSuccess == YES) {
        [self thingE];
    }
    [self thingF];

    return;
}

提出的解决方案的直接明显问题是完成处理程序可以传递多个对象,而块的返回值只能处理1个对象。但是格式与此类似的东西?它更清洁,更易于维护。

1 个答案:

答案 0 :(得分:5)

我认为您已发现调度组

关于它们的文章有1000篇,不需要在这里毫无意义地粘贴一些东西,

Wait until multiple networking requests have all executed - including their completion blocks

喝彩!


在更简单的层面上,您可能正在寻找的仅仅是“分离代码”,这是写作的关键部分,简单,整洁的代码。请注意,这并不总是解决方案,但经常 - 而且,我并不是100%清楚你要问的是什么。但是在脱离代码中,你会这样......

{
do something;
if ( failure, and you don't want to do any more ) return;
do some other important thing;
if ( failure of that thing, and you don't want to do any more ) return;
do yet another routine here;
if ( some other failed conditions, and you don't want to do any more ) return;
}

这是一个典型的例子。通常你会看到像这样的代码......

-(void)loadNameInToTheCell
  {
  if ( self.showname != nil && [self.showname notLike:@"blah"] && kount<3 )
        {
        // many many lines of code here
        // many many lines of code here
        // many many lines of code here
        }
  }
你和我在一起吗?但是这样写它会好得多:

-(void)loadNameInToTheCell
  {
  if ( self.showname == nil ) return;
  if ( [self.showname notLike:@"blah"] return;
  if ( kount<3 ) return;

  // many many lines of code here
  // many many lines of code here
  // many many lines of code here
  }

有道理吗?

请注意,在任何实际项目中,关键是文档而不是代码,所以你可以正确地讨论和评论......

-(void)loadNameInToTheCell
  {
  if ( self.showname == nil ) return;
  // don't forget Steve's routine could return nil

  if ( [self.showname notLike:@"blah"] return;
  // should we worry about caps here?

  if ( kount<3 ) return;
  // client wants to change this to 4 in future - Steve
  // screw that ... Biff, 8/2014

  // many many lines of code here
  // many many lines of code here
  // many many lines of code here
  }

有道理吗?我希望这有助于你所要求的。你必须想到你知道的“其他方式”吗?

一个可能的经验法则是,如果你有条件,然后是“非常长的代码块” - 那就错了。转向另一个方向,并有突破条件。只有这样,才有“实际的相关代码”。从某种意义上说,永远不要在if块中放置一长串重要的代码;如果是这样的话,你有点想错了。