2

サーバー上のメッセージを削除するためにサーバーを呼び出すために一度に複数の Web サービス要求を呼び出す必要がある状況にあり、データを更新するためのいくつかのメソッドをトリガーする最良の方法を見つけようとして苦労しています。これらの Web サービス呼び出しのグループが完了したとき。

セマフォカウンターを使用して調査したことから、やりたいことにはうまくいくはずですが、セマフォトークンでdispatch_release()を呼び出すと、アプリケーションがこれでクラッシュするという問題が発生しています-

libdispatch.dylib`_dispatch_semaphore_dispose$VARIANT$mp:
0x3c03ed70:  push   {r7, lr}
0x3c03ed72:  ldr    r1, [r0, #40]
0x3c03ed74:  mov    r7, sp
0x3c03ed76:  ldr    r2, [r0, #36]
0x3c03ed78:  cmp    r1, r2
0x3c03ed7a:  bge    0x3c03ed7e                ; _dispatch_semaphore_dispose$VARIANT$mp + 14
0x3c03ed7c:  trap   

この問題で私が見つけたものはすべて、セマフォトークンが何かによって参照されていることを示していますが、何がトークンを参照しているのかわかりません。

- (void)deleteMultipleThreadsForMessages:(NSArray *)messages withCompletion:(void(^)(BOOL allThreadsDeleted))completion
{
    NSDictionary *userDictionary = [[MSMKeychainAccess sharedKeychain] returnUserDictionary];

    long messagesCount = [messages count] - 1;

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(messagesCount);

    BOOL (^isLastRequest)(void) = ^BOOL (void) {
        long result = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW);
        if (0 == result) {
            return false;
        }
        dispatch_release(semaphore);
        return true;
    };

    for (MSMMessageDataModel *message in messages) {
        NSDictionary *dictionary = @{@"license": userDictionary[@"license"],
                                     @"messageID" : message.msgID};
        NSLog(@"Called this many times! %@", message.msgID);
        [[MSMClient sharedClient] soapPostsWithCompletion:^(NSDictionary *response, NSError *error) {
            if (error) {
                isLastRequest();

                completion(NO);
            } else {
                if (isLastRequest()) {
                    completion(YES);
                }
            }
        } andRequest:[[[MSMRequestsController alloc] init] createGetMessagesSOAPCallAndSendRequest:@"DeleteThread"
                                                                         withParameters:dictionary]];
    }
}

編集

素晴らしい答えをありがとう。ダスティンが言ったように、私はdispatch_semaphoreを使用すべきではないものに使用しようとしていました。実装が簡単で、Web サービスを送信するために現在行っていることを再構築する必要がなかったため、彼の回答を受け入れました。しかし、dispatch_groups全般については、良い読み物があります。

ご助力いただきありがとうございます!

4

3 に答える 3

2

これはまさにdispatch_group対処するために設計されたものです。いくつかのブロックをグループにディスパッチし、それらがすべて完了すると、別のブロックが実行されます (または、同期動作が必要な場合はそれらを待つことができます)。

最初に、同時実行プログラミング ガイドの「キューに入れられたタスクのグループでの待機」を参照し、 GCD リファレンスdispatch_groupの関数を参照してください。それらの動作を確認するには、 iOS:PTLの第 13 章のJuliaCellの例を参照してください。ココアサムライにもいくつかの例があります。

実際にブロックをグループにディスパッチできなくても ( のMSMClient動作方法では機能しない可能性があります)、ディスパッチ グループを手動で呼び出して使用dispatch_group_enter()dispatch_group_leave()、セマフォから得ようとしているのと同じ動作を得ることができます。

補足として、BOOLは と同じではありませんboolBOOLreturn YESand 、これはandNOとは異なります (これは、これを ObjC++ としてコンパイルしていることを意味すると思いますが、これは常に私を身震いさせますが、それは別の問題です)。サイズが異なる場合があるため(場合によっては異なる場合もあります)、それらを混在させることは重要です。私は個人的にそのためにクラッシュしなければなりませんでした。truefalse

于 2013-06-05T02:19:41.730 に答える
1

これは、dispatch_semaphore の間違った使い方です。あなたが試みていることを意図したものではありません。必要なのは、スレッドセーフなカウント変数です。これは __sync_sub_and_fetch を使用して取得できます。

- (void)deleteMultipleThreadsForMessages:(NSArray *)messages withCompletion:(void(^)(BOOL allThreadsDeleted))completion
{
    NSDictionary *userDictionary = [[MSMKeychainAccess sharedKeychain] returnUserDictionary];

    __block long messagesCount = [messages count];

    for (MSMMessageDataModel *message in messages) {
        NSDictionary *dictionary = @{@"license": userDictionary[@"license"],
        @"messageID" : message.msgID};
        NSLog(@"Called this many times! %@", message.msgID);
        [[MSMClient sharedClient] soapPostsWithCompletion:^(NSDictionary *response, NSError *error) {
            long which = __sync_sub_and_fetch(&messageCount, 1);
            if(which == 0)
                completion(error == nil);
        } andRequest:[[[MSMRequestsController alloc] init] createGetMessagesSOAPCallAndSendRequest:@"DeleteThread"
                                                                                    withParameters:dictionary]];
    }
}

__sync_sub_and_fetch は、すべてのスレッド (およびコア) から最新バージョンの 'messageCount' を取得し、1 を減算して結果を返すように CPU に指示します。

于 2013-06-05T00:45:45.080 に答える