【问题标题】:Avoiding nested blocks with asynchronous code in objective-c在objective-c中避免使用异步代码嵌套块
【发布时间】:2014-08-10 12:37:22
【问题描述】:

我的 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 个对象。但是格式与此类似的东西?它非常清洁且易于维护。

【问题讨论】:

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


    【解决方案1】:

    我想你已经发现了调度组

    上面有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 块中放置一长串重要代码;如果是这样,你的想法有点不对。

    【讨论】:

    • 希望有帮助,请随时询问任何后续
    • 问题是我的代码大多是异步的。对调度组的快速测试表明它根本不尊重当前线程之外的代码,这使得它对我没有用处。除非我错过了什么?
    • 您知道,我强烈建议您就此提出一个新问题,展示您的“异步调度组灾难!”的示例。 - 你知道的这个当前问题对你没有任何吸引力吗?
    猜你喜欢
    • 1970-01-01
    • 2014-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-13
    相关资源
    最近更新 更多