Ios 两种方法的竞争和一次运行完成方法

Ios 两种方法的竞争和一次运行完成方法,ios,objective-c,cocoa,Ios,Objective C,Cocoa,我有三种方法,其中两种同时运行。第三种方法只有在第一种和第二种方法共同完成工作后才能开始。第一种或第二种方法,即竞争对手,都可以先完成他们的工作 - (void)method1 { //DO Long Work isMethod1Complete = YES; [self method3]; } - (void)method2 { //DO Long Work isMethod2Complete =

我有三种方法,其中两种同时运行。第三种方法只有在第一种和第二种方法共同完成工作后才能开始。第一种或第二种方法,即竞争对手,都可以先完成他们的工作

- (void)method1 {
        //DO Long Work
        isMethod1Complete = YES;
        [self method3];
    }

    - (void)method2 {
        //DO Long Work
        isMethod2Complete = YES;
        [self method3];
    }

    - (void)method3 {
        if (isMethod1Complete && isMethod2Complete) {
            //DO Work once
        }
    }
方法3应该总是调用一次。但问题是,有一种情况是method1和method2同时完成了工作,method3被调用了两次。告诉我如何在iOS的目标c中解决此问题

更新:一个具体的例子,我有两个服务,在代理完成工作时调用他们

- (void)method1Handler {
        isMethod1Complete = YES;
        [self method3];
}

- (void)method2Handler {
        isMethod1Complete = YES;
        [self method3];
}
如何在没有障碍的情况下解决这一问题? 对于积木,罗布的例子是最好的。

你说:

- (void)viewDidLoad {
[super viewDidLoad];
[self method1];
[self method2];
}


- (void)method1 {
    //DO Long Work
    isMethod1Complete = YES;

}

- (void)method2 {
    //DO Long Work
    isMethod2Complete = YES;
    dispatch_async(dispatch_get_main_queue(), ^(void){
    [self method3];
  }
}

- (void)method3 {
    if (isMethod1Complete && isMethod2Complete) {
        //DO Work once
    }
}
我有三种方法,其中两种同时运行

这意味着它们必须是异步的或在后台队列上运行(否则它们无法同时运行)

因此,您应该给它们两个完成处理程序(完成后将调用它们):

在上面的示例中,我向后台队列添加了显式的
dispatch\u async
调用,以确保两个长任务异步运行。但是,如果代码已经在执行异步操作(例如网络请求),那么您可能不需要这些
dispatch\u async
调用,只需将
completion()
调用放在您已经使用的任何API提供的完成处理程序中即可。但是如果没有更多关于
method1
method2
的信息,我就不能说得更具体了

但是,撇开这一点不谈,一旦您的
method1
method2
有了自己的完成处理程序,您就可以使用它们来确定当所有调用都被相应的调用平衡时应该做些什么:


在随后的评论中,您提到您使用的不是基于完成块的API,而是基于委托协议的API。您有几个选项,例如:

  • 您可以使用上述相同的闭包模式,但只需将完成处理程序保存为块属性,例如:

    例如,定义块特性:

    @property (nonatomic, copy, nullable) void (^completionOne)(void);
    @property (nonatomic, copy, nullable) void (^completionTwo)(void);
    
    然后,您的
    method1
    method2
    将保存这些块:

    - (void)method1WithCompletion:(void(^ _Nonnull)(void))completion {
        self.completionOne = completion;
    
        // start your time consuming asynchronous process
    }
    
    // and your completion delegate method can then call the saved closure
    // and then remove it
    
    - (void)method1DidComplete {
        self.completionOne();
        self.completionOne = nil;
    }
    
    - (void)method2WithCompletion:(void(^ _Nonnull)(void))completion {
        self.completionTwo = completion;
    
        // start second asynchronous process
    }
    
    // same as above
    
    - (void)method2DidComplete {
        self.completionTwo();
        self.completionTwo = nil;
    }
    
    然后,委托协议完成API将只调用保存的块属性(并可能将它们重置为
    nil
    ,以释放与这些块关联的内存)

    然后您可以使用调度组通知流程,如上面我的原始答案所示

  • 或者,您可以单独使用dispatch group,而不是使用块。例如,定义调度组属性:

    @property (nonatomic, strong, nullable) dispatch_group_t group;
    
    然后,创建组并开始两项任务:

    self.group = dispatch_group_create();
    
    [self method1];
    
    [self method2];
    
    dispatch_group_notify(self.group, dispatch_get_main_queue(), ^{
        [self method3];
    });
    
    然后,当您启动任务时,这两种方法在各自的完成处理程序委托方法中输入
    dispatch\u group\u
    ,然后离开

    - (void)method1 {
        dispatch_group_enter(self.group);
    
        // start first asynchronous process
    }
    
    // in your delegate completion method, you "leave" the group
    
    - (void)method1DidComplete {
        dispatch_group_leave(self.group);
    }
    
    - (void)method2 {
        dispatch_group_enter(self.group);
    
        // start second asynchronous process
    }
    
    - (void)method2DidComplete {
        dispatch_group_leave(self.group);
    }
    
    - (void)method3 {
        // you might as well remove the group now that you're done with it
    
        self.group = nil;
    
        // final task
        NSLog(@"doing three");
    }
    
  • 就我个人而言,我通常倾向于第一种选择(这样,分派组内容包含在一个方法中),但这两种方法都有效。

    为什么不在串行队列中分派对method3的“调用”

    dispatch_queue_t notSimQ;
    notSimQ = dispatch_queue_create("notSimQ", NULL);
    
    - (void)method1 {
        //DO Long Work
        isMethod1Complete = YES;
        dispatch_async( notSimQ, // or sync
        ^{ 
          [self method3]; 
        });
    }
    
    - (void)method2 { … } // similiasr
    
    - (void)method3 { … } // unchanged
    

    对method3的调用从来没有竞争过。

    为什么不使用块?这是做这件事的标准方法。只需在当前正在调用的块中调用
    method3
    …我使用的两个服务基于委托,我无法更改它=(好的,将完成处理程序保存在块属性中,并让您的代理从中调用它们。或者,将
    dispatch\u group\u t
    变量保存在属性中。但调度组是跟踪一系列异步任务何时完成的最佳方法。其他选项包括
    NSOperation
    依赖项、被动模式和erns等,但调度组是最好的。它使您摆脱了维护一堆状态属性(您可能必须同步这些属性才能使线程安全)及其可伸缩性的麻烦。您能举一个小例子说明如何在委托中调用组块吗?我试过了,我仍然有一个方法工作了两次(请参阅下面我的修订答案,其中我展示了使用基于代理协议的API而不是像这样的基于块的API.call方法时的两个选项。)
    - (void)method1 {
    //DO Long Work
    isMethod2Complete = YES;
     dispatch_async(dispatch_get_main_queue(), ^(void){
    [self method3];
      }
        }
    
    - (void)method2 { … } 
    
    - (void)method3 { … } 
    
    dispatch_queue_t notSimQ;
    notSimQ = dispatch_queue_create("notSimQ", NULL);
    
    - (void)method1 {
        //DO Long Work
        isMethod1Complete = YES;
        dispatch_async( notSimQ, // or sync
        ^{ 
          [self method3]; 
        });
    }
    
    - (void)method2 { … } // similiasr
    
    - (void)method3 { … } // unchanged
    
    - (void)method1 {
    //DO Long Work
    isMethod2Complete = YES;
     dispatch_async(dispatch_get_main_queue(), ^(void){
    [self method3];
      }
        }
    
    - (void)method2 { … } 
    
    - (void)method3 { … }