4

最初の非同期通信の完了ブロックで別の新しい非同期メソッドを開始する方法のベストプラクティスを知っている人はいますか?

Facebookへの別の非同期通信の完了コールバックで非同期にNSFetchRequest(coz STACKMOB iOS SDKがサーバーと内部的に同期する)を呼び出すコードをテストしています。コードの実行は、NSFetchRequest の行で突然終了します。うまく動かない原因の一つが分かりました。[managedObjectContext executeFetchRequest:fetchRequest error:&error] が呼び出されるとすぐに、完了ブロックがメモリから解放されたと思います。しかし、それを修正するためのより良い解決策がわかりません。助けてくれてありがとう。

SDK は以下を使用します。

  • (void)queueRequest:(NSURLRequest *)リクエスト オプション:(SMRequestOptions *)オプション onSuccess:(SMFullResponseSuccessBlock)onSuccess onFailure:(SMFullResponseFailureBlock)onFailure

https://github.com/stackmob/stackmob-ios-sdk/blob/master/Classes/SMDataStore%2BProtected.m

私は試した:

:

- (IBAction)checkFacebookInfo:(id)sender
{
    //completion block of facebook info
    void(^onCompleteBlock)(NSDictionary*) = [[^(NSDictionary* userInfo)
    {
        NSManagedObjectContext *managedObjectContext = nil;
        managedObjectContext = [[SingletonCoreData sharedManager] managedObjectContext];

        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"User"];

        //for STACKMOB, customized NSFetchRequest internally sync to the server. It is Asynchronous method.
        NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];// failed

        //Not reached here
        //set userInfo to results here

    } copy] autorelease];

    //invoke onCompleteBlock after executing asynchronously, client(SMClient object for STACKMOB)
    [client getLoggedInUserFacebookInfoWithOnSuccess:onCompleteBlock onFailure:^(NSError *error)
     {

         NSLog(@"No user found");

     }];

}

編集済み: これを以下に書いてみましたが、うまくいきました。しかし、私はそれが遅いと感じます。コードの一部を「dispatch_async」ブロックに入れました。他のより良い解決策を待っています。

    - (IBAction)checkFacebookInfo:(id)sender
    {
        //completion block of facebook info
        void(^onCompleteBlock)(NSDictionary*) = ^(NSDictionary* userInfo)
        {

            dispatch_queue_t gQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

            dispatch_async(gQueue, ^{
                NSManagedObjectContext *managedObjectContext = nil;
                managedObjectContext = [[SingletonCoreData sharedManager] managedObjectContext];

                NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"User"];

                //for STACKMOB, customized NSFetchRequest internally sync to the server. It is Asynchronous method.
                NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];// success

                //set userInfo to results here

            });

        };

        //invoke onCompleteBlock after executing asynchronously, client(SMClient object for STACKMOB)
        [client getLoggedInUserFacebookInfoWithOnSuccess:onCompleteBlock onFailure:^(NSError *error)
         {

             NSLog(@"No user found");

         }];

}
4

1 に答える 1

0

複数の非同期操作を (ネットワーク経由またはその他の方法で) 同期しようとしている場合、promise を使用することはあまりお勧めできません。promise の概要については、Los Techies の最近のブログ エントリが非常に優れています。

http://lostechies.com/derickbailey/2012/07/19/want-to-build-win8winjs-apps-you-need-to-understand-promises/

KSPromiseそうは言っても、私が iOS でかなり使用したという優れたライブラリがあります: https://github.com/kseebaldt/deferred

promise を使用すると、1 つ以上の非同期呼び出しが完了した後にフェッチ リクエストを行うことができます。たとえば、join promise は、依存するすべての promise も解決された後にのみ解決されます! 特に複雑なことをしている場合は、promise を使用すると、コードがより整理されて読みやすくなることがわかると思います。

そうは言っても、promise を使用してコードを記述する方法を示す、かなり不自然な例を次に示します (記述と Facebook iOS 3.1 SDK の比較):

- (IBAction)checkFacebookInfo:(FBSession *)session {
  KSDeferred *dfd = [KSDeferred defer];

  FBRequest *meRequest = [[FBRequest alloc] initWithSession:session graphPath:@"/me"];
  [meRequest startWithCompletionHandler:
    ^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
      if (error) {
        [dfd.promise rejectWithError:error];
      } else {
        [dfd.promise resolveWithValue:user];
      }
  }];

  [dfd.promise whenResolved:^(KSPromise *p) {
    NSDictionary *userInfo = p.value;
    NSManagedObjectContext *managedObjectContext = [[SingletonCoreData sharedManager] managedObjectContext];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"User"];
    NSError *error;
    NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
    // Do whatever with results and userInfo here
  }];

  [dfd.promise whenRejected:^(KSPromise *p) {
    NSError *e = (NSError *)p.value;
    NSLog(@"Error: %@", [e localizedDescription]);
  }];
}

最後にもう 1 つ: Core Data をスレッドおよびdispatch_async. デバッグが困難なあらゆる種類の並行性の問題に遭遇する可能性があります。

于 2012-12-16T00:49:19.560 に答える