【问题标题】:How to make FetchRequest in callback block asynchronously如何在回调块中异步制作 FetchRequest
【发布时间】:2012-11-08 11:52:30
【问题描述】:

有谁知道如何在第一次异步通信的完成块中启动另一个新的异步方法的最佳实践?

我正在测试代码以在另一个与 Facebook 的异步通信的完成回调中异步调用 NSFetchRequest(coz STACKMOB iOS SDK 在内部与服务器同步)。代码的执行突然在 NSFetchRequest 行终止。我意识到它无法正常工作的原因之一。 我猜想一旦 [managedObjectContext executeFetchRequest:fetchRequest error:&error] 被调用,完成块就已经从内存中释放了。 但我不知道更好的解决方案来解决它。感谢您的帮助。

SDK 使用:

  • (void)queueRequest:(NSURLRequest *)request options:(SMRequestOptions *)options 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");

         }];

}

【问题讨论】:

  • 您是否尝试过在 alloc/init 之后使用 retain 调用 fetcheRequest,然后在使用它调用 release 之后调用?
  • 谢谢 yulz,我试过了,但对我不起作用。
  • 首先,你不需要复制和自动释放块。 “问题可能是它在 NSFetchRequest 完成之前从内存中释放调用者块” 什么?这种说法没有任何意义

标签: objective-c asynchronous objective-c-blocks nsfetchrequest stackmob


【解决方案1】:

如果您尝试同步多个异步操作(通过网络或其他方式),我不推荐使用 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,您可以在一个或多个异步调用完成后发出 fetch 请求。例如,一个连接承诺只有在其所有依赖的承诺也都解决后才会被解决!我想你会发现使用 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]);
  }];
}

最后一件事:在使用带有线程和dispatch_async 的Core Data 时要非常非常小心。您可能会遇到各种难以调试的并发问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-03
    • 1970-01-01
    相关资源
    最近更新 更多