0

iOS でのマルチスレッドは初めてです。API から情報を取得し、情報を解析して、データベースに保存するという 3 つのことを行う必要があります。私はこれらの 3 つを別のファイル (getAPI、parseAPI、savetoDB) に入れています。getAPI は parseAPI を呼び出し、その代わりに savetoDB を呼び出します。3 つすべてがバックグラウンド スレッドで動作するようにします。

私の質問は、getAPI を呼び出すときに、parseAPI と savetoDB もバックグラウンド スレッドで実行されるかどうかです。3 つすべてがバックグラウンドで実行されるようにするにはどうすればよいですか? savetoDB の後に呼び出しをメインスレッドに戻すにはどうすればよいですか?

例:

dispatch_queue_t backgroundQueue;
backgroundQueue = dispatch_queue_create("lakesh", NULL);  
- (void)startprocess {    
    dispatch_async(backgroundQueue, ^(void) {
        [self getAPI];
    });    
}

いくつかのガイダンスが必要..ありがとう...

4

3 に答える 3

2

バックグラウンド スレッドで関数を発行すると、そのスレッドが終了するか、メイン スレッドで別の関数をコールバックするまで、すべての実行がそのスレッドで続行されます。最初はあなたと同じように悩んでいたので、以下のマクロを自作しました。

/// Stick this in code you want to assert if run on the main UI thread.
#define DONT_BLOCK_UI() \
    NSAssert(![NSThread isMainThread], @"Don't block the UI thread please!")

/// Stick this in code you want to assert if run on a background thread.
#define BLOCK_UI() \
    NSAssert([NSThread isMainThread], @"You aren't running in the UI thread!")

コメントからわかるように、私はこれらのマクロをメソッドの先頭で使用する傾向があり、間違ったスレッドで誤って使用していないことを確認します。これらのマクロとその他のランダムなものをhttps://github.com/gradha/ELHASO-iOS-snippetsに置いたので、役に立つと思います。

メインスレッドへの復帰に関する質問に関しては、GCD を使用しているため、そこで実行したいコードをdispatch_get_main_queue()最後に呼び出すのが最善です。savetoDBがライブラリ関数の場合savetoDB、そのエントリ ポイントでは、すべてが終了したときにメイン スレッドで実行する成功ブロックを渡すことができる必要があります。これは、 https://github.com/AFNetworking/AFNetworkingなどのライブラリで使用されるパターンです。それらの例が、バックグラウンドで実行され、コードがコールバックされる (通常はメイン スレッドで) API を提供する方法に注意してください。

于 2013-02-09T13:26:53.450 に答える
1

はい、もちろん、getAPI呼び出しparseAPIの場合、コードparseAPIは実行されたスレッドと同じスレッドでgetAPI実行されるため、この例ではバックグラウンド キューで実行されます。

completionBlock最後にコールバックをメイン スレッドに戻すには、複数の Apple API で見られるようにApple が使用するのと同じテクニックを使用しdispatch_block_tますvoid(^)(NSError*)getAPI:に渡すparseAPI:と、次にそれが渡さsavetoDB:れ、最後に、メインスレッドでこのコードブロック (メソッドからメソッドに渡される) を呼び出すためにsavetoDB:使用できます。dipatch_async(dispatch_get_main_queue, completionBlock);

注: getAPI の場合、Apple のsendAsynchronousRequest:queue:completionHandler:メソッドを使用できます。これにより、バックグラウンドでリクエストが自動的に実行され、指定された完了ブロックが呼び出されますNSOperationQueue( NSOperationQueueGCD の dispatch_queue を内部で使用します)。詳細についてはNSOperationQueue、GCD およびConcurrency Programming Guideのドキュメントと、Apple doc のすべての詳細なガイドを参照してください。


-(void)getAPI:( void(^)(NSError*) )completionBlock
{
  NSURLRequest* req = ...
  NSOperationQueue* queue = [[NSOperationQueue alloc] init]; // the completionHandler will execute on this background queue once the network request is done
  [NSURLConnection sendAsynchronousRequest:req queue:queue completionHandler:^(NSURLResponse* resp, NSData* data, NSError* error)
   {
     if (error) {
       // Error occurred, call completionBlock with error on main thread
       dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(error); });
     } else {
       [... parseAPI:data completion:completionBlock];
     }
   }];
}

-(void)parseAPI:(NSData*)dataToParse completion:( void(^)(NSError*) )completionBlock
{
   ... parse datatToParse ...

   if (parsingError) {
     dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(error); });
   } else {
     [... savetoDB:dataToSave completion:completionBlock];
   }
}

-(void)savetoDB:(id)dataToSave completion:( void(^)(NSError*) )completionBlock
{
   ... save to your DB ...

   // Then call the completionBlock on main queue / main thread
   dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(dbError); }); // dbError may be nil if no error occurred of course, that will tell you everything worked fine
}

-(void)test
{
  [... getAPI:^(NSError* err)
   {
      // this code will be called on the main queue (main thread)
      // err will be nil if everythg went OK and vontain the error otherwise
   }];
}
于 2013-02-09T13:15:25.577 に答える
1

はい、作成した新しいキューparseAPIsavetoDB実行されます。操作が終了したときに UI を変更する必要がある場合は、そのコードをメイン スレッドで実行する必要があります。これを行うには、メイン キューへの参照を取得し、コードを送信します。例えば:

- (void)startprocess {    
    dispatch_async(backgroundQueue, ^(void) {
        [self getAPI];
        dispatch_async(dispatch_get_main_queue(), ^{
             // Refresh the UI with the new information
        });
    });    
}

dispatch_release完了したら、新しいキューを忘れないでください。

フレームワークの多くの部分で Cocoa 自体によって使用される別のパターンは、バックグラウンド操作が終了したときに呼び出される API 関数のシグネチャにコールバック ブロックを追加することです。このスタック オーバーフロー スレッドでは、その方法について説明しています。

于 2013-02-09T13:16:32.543 に答える