【问题标题】:How to make particular part of function wait in iOS如何在iOS中使特定部分功能等待
【发布时间】:2014-01-17 10:51:03
【问题描述】:

我正在尝试执行共享操作,在该操作中我使用异步块调用函数,但在下一个 if 语句中,我需要获取在块中完成的值才能继续。这是我的代码,它将突出显示更多细节。我听说过NSLock,也试过用了,但是没用,可能是我在做锁,我对锁不太熟悉。

-(void) shareOperation
{
__block NSString *resultText;
BOOL continueSharing;
 NSLock *conditionLock=[[NSLock alloc] init];
         dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{
            [conditionLock lock];
        [self performSomeAsynchronousOperation completionBlock:^(NSError *tError, bool status)
         {
             dispatch_async(dispatch_get_main_queue(),
                            ^{

                                if (status)
                                {
                                    resultText = @"Operation completed. Would you like to continue?";

                                }
                                else
                                {
                                    resultText = @" Operation failed. Would you still like to continue?";
                                }
                                UIAlertView *result = [UIAlertView alertViewWithTitle:nil message:resultText cancelButtonTitle:@"Cancel" otherButtonTitles:[NSArray arrayWithObjects:@"OK",nil] onDismiss:^(int buttonIndex)
                                                       {
                                                           NSLog(@"selected button index: %d",buttonIndex);
                                                           if (buttonIndex == 0)
                                                           {
                                                               continueSharing=YES;
                                                               [conditionLock unlock];
                                                               NSLog(@"We are continuing sharing :)");
                                                           }
                                                       }onCancel:^{
                                                           continueSharing=NO;
                                                            [conditionLock unlock];
                                                           NSLog(@"cancelled");
                                                       }]; [result show];

                            });
         }];
        });
    }


    //should continue only after earlier if block finishes, ie after getting the continueSharing value

    if (continueSharing)
    {
        [self performSomeAnotherAsynchronousOperation];
    }

}

【问题讨论】:

标签: ios iphone objective-c objective-c-blocks nslock


【解决方案1】:

您可以使用信号量(其设计目的是让一个线程可以等待来自另一个线程的信号,这是必需的在这里)。

所以,你应该创建一个信号量:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

警报视图完成块会发出该信号量的信号:

dispatch_semaphore_signal(semaphore);

以及您想在哪里等待该信号(performSomeAnotherAsynchronousOperation 之前):

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

我稍微调整了您的代码,但最值得注意的是,通过确保 dispatch_semaphore_wait 在后台队列中完成,它不会阻塞主队列(您永远不想这样做)。另请注意,dispatch_semaphore_signal 不在if 语句中。结果是:

- (void)shareOperation
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __block BOOL continueSharing = NO;
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

        [self performSomeAsynchronousOperationWithCompletionBlock:^(NSError *tError, bool status){
            dispatch_async(dispatch_get_main_queue(),^{
                NSString *resultText;

                if (status)
                    resultText = @"Operation completed. Would you like to continue?";
                else
                    resultText = @"Operation failed. Would you still like to continue?";

                UIAlertView *alertView = [UIAlertView alertViewWithTitle:nil message:resultText cancelButtonTitle:@"Cancel" otherButtonTitles:@[@"OK"] onDismiss:^(int buttonIndex) {
                    NSLog(@"selected button index: %d",buttonIndex);
                    if (buttonIndex == 0) {
                        continueSharing = YES;
                        NSLog(@"We are continuing sharing :)");
                    }
                    dispatch_semaphore_signal(semaphore);
                } onCancel:^{
                    dispatch_semaphore_signal(semaphore);
                    NSLog(@"cancelled");
                }];

                [alertView show];
            });
        }];

        // should continue only after earlier if block finishes, ie after getting the continueSharing value

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

        if (continueSharing)
            [self performSomeAnotherAsynchronousOperation];
    });
}

更好的是,您不应该使用任何阻塞机制,如信号量(当然不在主队列上),而应该简单地让警报视图的完成块直接启动流程的下一步。我了解您说这在您的场景中不实用,但通常是处理这些场景的正确方法。

【讨论】:

  • 选项3对我来说不是一个选项,因为我的实际代码中有很多嵌套操作,这段代码只是为了说明问题,我尝试了第一个选项但得到了 [NSLock lock]: deadlock ,我不熟悉信号量,所以现在研究如何实现它。感谢您的回复。
  • 我尝试了信号量但同样的问题 UI 挂起,我认为有不同的问题,实际上我的 [self performSomeAsynchronousOperation completionBlock...] 方法应该会带来一个弹出窗口,当我点击该弹出窗口上的确定按钮将返回状态,然后只会显示警报视图。我认为弹出窗口也处于等待模式,因为它永远不会出现。如果是这样,我应该如何处理这种情况?
  • 我该怎么做?,我尝试将我的初始函数添加到 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);但这没有帮助
  • @Gamerlegend 好的,退后一步:1. 锁确实不是一个合适的解决方案,所以我已经完全从我的回答中删除了它。简单的NSLock 不起作用,但尝试补救它是没有意义的。 2. 鉴于您的 cmets,我测试了修改后的信号量答案,它似乎有效,但我提供了更完整的代码示例供您查看。我清理了您的代码示例中的一些内容,请看一下。
  • 3.就您的performSomeAsynchronousOperation 竞争警报视图问题而言,很难说没有有关performSomeAsynchronousOperation 工作原理的详细信息,特别是在调用完成处理程序时与它显示的警报相关。是在您解除此 performSomeAsynchronousOperation 的警报视图已显示/解除的警报之前还是之后调用完成处理程序?
【解决方案2】:

你可以使用延迟块

 dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC);

    dispatch_after(delayTime, dispatch_get_main_queue(), ^(void){

    })

【讨论】:

    猜你喜欢
    • 2020-10-31
    • 1970-01-01
    • 2021-08-23
    • 2017-09-29
    • 1970-01-01
    • 2021-03-17
    • 2019-04-22
    • 2020-08-14
    • 2021-10-29
    相关资源
    最近更新 更多