3

我相信我的用例相当普遍,但我找不到任何能让我 100% 确定自己在做什么的文档。任何指针表示赞赏。

在我的应用程序的某个时刻,我开始下载一个对象。之后,用户可以单击按钮。如果对象完成下载,我想执行一些代码。否则我想等到对象被下载并执行相同的代码。如果用户不点击按钮,我不想做任何事情。下载的对象丢失。

我的基本想法是做这样的事情:

NSObject *myObj = nil;

- (void)download {
  [self downloadObj:^(NSObject *obj){
    myObj = obj;
  }];
}

- (void)buttonClicked {
  waitOrExecuteDirectly:^{
    // Some code with myObj
  }
}

当然,第一个问题是“我该如何等待?”

所以我尝试了

- (void)buttonClicked {
  if(myObj) {
    // Some code
  } else {
    // Wait then do the exact same code
  }
}

但我认为更棘手的问题是“如果在计算“if”之后和输入“else”块之前对象完成下载会发生什么?

我试图将下载封装在一个NSOperation并使用该completionBlock属性。但是,如果在我设置回调时操作已经完成,则永远不会调用 completionBlock。我不想在“下载”方法中设置回调,因为用户可能不会点击按钮。

是否有内置机制允许我根据任务状态为将等待或直接执行的任务提供完成回调?如果没有,我自己做的最佳做法是什么?NSLock设置和阅读时使用myObj?

4

3 回答 3

4

这是代码示例:

    - (void)download {
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        [self downloadObj:^(NSObject *obj){
            myObj = obj;
            dispatch_semaphore_signal(sema);
        }];
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        dispatch_release(sema);
    }
于 2013-11-06T08:09:47.720 回答
0

我认为你不应该在主线程上等待,因为这会阻塞整个用户界面。我的方法是这样的:

typedef MyOperation void (^)(NSData * myData);

...

@private MyOperation _operationWhenDownloadFinished; // instance variable
@private NSData * _data

...

-(void)buttonPressed{
   [self waitAndPerformOperation:^(NSData * myData){ ... }];
}

-(void)waitAndPerformOperation:(MyOperation)operation{
   if(_data != nil){
       operation(myData);
      _operationWhenDownloadFinished = nil;
   }else{
      _operationWhenDownloadFinished = operation;
   }
}

...

-(void)downloadFinished:(NSData*)downloadedData{ // this is called on the main thread, e.g. by an NSURLConnection delegate
   _data = downloadedData;
   if(_operationWhenDownloadFinished != nil){
      [self waitAndPerformOperation:_operationWhenDownloadFinished];
   }
}

由于按钮按下和 downloadFinished 委托回调都发生在主线程上,我们可以毫不费力地避免任何竞争条件。

于 2013-11-06T08:11:09.760 回答
0

您可以使用 dispatch_semaphore_t 来完成此操作。创建计数为 0 的信号量,在 buttonClicked 中等待它,在设置 myObj 后发出信号。

如果单击按钮时尚未发出信号,它将阻塞(注意:您可能不希望在这里阻塞主线程任意时间......)直到信号量发出信号。如果信号量首先发出信号,则等待将简单地将其返回到其原始状态而不会阻塞。

烦人的是,没有与 dispatch_group_notify 等效的信号量,所以如果你想在后台等待下载完成,你需要阻塞一个线程等待。

于 2013-11-06T08:04:35.673 回答