核心数据使用完成处理程序执行获取请求或在主线程以外的其他线程中执行

Posted

技术标签:

【中文标题】核心数据使用完成处理程序执行获取请求或在主线程以外的其他线程中执行【英文标题】:Core Data Performing Fetch Request with Completion Handler or execute in some other thread other than Main thread 【发布时间】:2017-04-03 09:48:17 【问题描述】:

在我的 ios 应用程序中,我使用的是 Core Data。 对于表视图列表,我使用 NSFetchedResultsController 和 连接到远程存储我使用 NSIncrementalStore。

我的 FetchedResultsController 上下文具有 MainQueue Cuncurrency 类型。(我无法使用 PrivateQueueCurrencyTYpe 来做到这一点)。

为了解决故障,对于多关系,从我的 IncrementalStore 子类执行 executeFetchResultsCall:withContext:error 方法。

在 executeFetchResults 方法中,如果本地数据库中不可用,我将调用 API(连接到远程服务器)。

myarray = [object representationsForRelationship:@"manyconnection" withParams:nil];

现在我需要将返回的结果数组同步返回给 ExecuteFetchResultsMethod。此操作也应在主线程上执行。

所以我只有一个选项可以从服务器获取结果,这会导致 UI 在指定的睡眠时间内无响应。

-(RequestResult*)makeSyncJsonRequest

    __block RequestResult *retResult = [[RequestResult alloc] init];
    __block BOOL block = YES;

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

   dispatch_group_t group = dispatch_group_create();

   void (^resultBlock)(RequestResult*) = ^(RequestResult* result)
      if(!retResult.error)
          retResult = result;
      block = NO;
      dispatch_group_leave(group);
  ;

  // Add a task to the group
 dispatch_group_async(group, queue, ^
       // Some asynchronous work

       dispatch_group_enter(group);
       [self makeAsyncJsonRequestWithBlock:resultBlock];
 );

 // Do some other work while the tasks execute.
 // When you cannot make any more forward progress,
 // wait on the group to block the current thread.    
 dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
 return retResult;

由于上述操作在主线程执行,UI挂起。

为了让UI更流畅,我需要在其他线程中执行executeFetchrequest,这是不可能的。

它还期望返回结果数组。

是否有任何选项可以以完成处理程序的方式执行此操作?

任何可以正常工作的替代方法或设计。

非常感谢任何帮助。

【问题讨论】:

DispatchGroup 是您可能想要搜索的内容。 @shallowThought 尽管这对于我的场景来说确实是更好的实现,但主线程仍在等待发生某些事情。在这种情况下,要么结果应该出来,要么等待时间到期。 UI 挂在中间 我不明白你的评论。要不阻塞 UI 线程,请使用 dispatch_group_notify,而不是 dispatch_group_wait 是的,我已经尝试实现 dispatch_group_wait。如何使用 dispatch_group_notify 解决这个问题?我已经用 dispatch_group_wait 更新了我的代码。 换句话说:您正在尝试使异步方法同步而无需等待,这是不可能的。 【参考方案1】:

这是一个骨架,使用dispatch_group,假设您使用NSFetchedResultsController 来更新您的UITableView

@implementation ViewController

    - (void)viewDidLoad 
        [super viewDidLoad];
        // do your setup (FetchedResultsController and such)
        [self syncData];
    

    - (void)syncData
    
        NSArray<Entity*> *results = [self fetchData];
        BOOL needsUpdateFromServer = YES; // check your results and set this bool accordingly

        if (!needsUpdateFromServer) 
            return;
        

        __block ServerResponse *fromServer = nil;
        __block dispatch_group_t group = dispatch_group_create();
        dispatch_group_enter(group);
        [self loadDataFromServer:^(ServerResponse *response) 
            fromServer = response;
            dispatch_group_leave(group);
        ];

        dispatch_group_notify(group,dispatch_get_main_queue(),^
            [self persistData:fromServer];
            /*
             According to our discussion, you are using an NSFetchedResultsController. 
             So your tableView should update automatically after persisting the data.
             */
        ); 
    

    - (void)loadDataFromServer:(void (^)(ServerResponse *response))completion
    
        // [someDownloadService downloadDataFromServerInBackgroundWithCompletion:^(ServerResponse* response)
            dispatch_async(dispatch_get_main_queue(), ^
                completion(response);
            );
        // ];
    

    - (NSArray<Entity*>*)fetchData
    
        NSArray<Entity*> *results = nil;
        // fetch from core data and return it
        return results;
    

    - (void)persistData:(NSArray<ServerResponse*> *)serverResponses
    
        // parse whatever you get from server
        // ... and persist it using Core Data
    

@end

【讨论】:

以上是关于核心数据使用完成处理程序执行获取请求或在主线程以外的其他线程中执行的主要内容,如果未能解决你的问题,请参考以下文章

核心数据:获取背景并在主线程上使用 objectWithID,性能优势?

任务Task系列之异步编程(async and await)

Xamarin - 在主线程以外的线程上加载数据

MSDN搬运 之 [异步编程设计模式]

实体框架核心和多线程

在 iOS SWIFT 2 中取消获取请求 [关闭]