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

これを行うには、dispatch_semaphore_t を使用できます。カウント 0 でセマフォを作成し、buttonClicked で待機し、myObj を設定した後にシグナルを送信します。

ボタンがクリックされたときにまだ通知されていない場合、セマフォが通知されるまでブロックされます (注: ここで任意の時間メインスレッドをブロックしたくない場合があります...)。セマフォが最初に通知された場合、待機はブロックせずに単に元の状態に戻します。

厄介なことに、dispatch_group_notify に相当するセマフォがないため、ダウンロードが完了するまでバックグラウンドで待機する場合は、待機中のスレッドをブロックする必要があります。

于 2013-11-06T08:04:35.673 に答える
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 に答える