3

In my iOS application I am using Core Data. For table View listing I use NSFetchedResultsController and Connecting to Remote store I use NSIncrementalStore.

My FetchedResultsController Context is having MainQueue Cuncurrency type.(I couldn't do it with a PrivateQueueCurrencyTYpe).

For resolving Fault, for a many relationship, the executeFetchResultsCall:withContext:error method is executed from my IncrementalStore subclass.

Inside the executeFetchResults method, I will invoke the API (connecting to remote server) if it is not available in my local database.

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

Now I need the results array in return synchronously to be returned to the ExecuteFetchResultsMethod. Also this operation should be executed on Main thread.

So I am having only one option to fetch the results from server which causes the UI to unresponsive for the specified sleep time.

-(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;
}

As the above operation is being executed on main thread,the UI hangs.

Inorder to make the UI smoother, I need to carry out the executeFetchrequest in some other thread which is not possible.

It also expects the results array in return.

Is there any option to carry out this something like in a completion handler manner?

or

Any alternate methods or design to work this proper.

Any Help is highly appreciated.

Govind
  • 2,337
  • 33
  • 43
  • 1
    `DispatchGroup` is what you might want to search for. – shallowThought Apr 03 '17 at 10:41
  • @shallowThought Even though this is really better implementation for my scenario, the main thread still waiting for something to be happened. In this case also either the results should come or the waiting time should expire. The UI is hanged in between – Govind Apr 03 '17 at 11:48
  • 1
    I did not understand your comment. To not block the UI thread, use `dispatch_group_notify`, not `dispatch_group_wait`. – shallowThought Apr 03 '17 at 12:00
  • Yes I have tried implementing dispatch_group_wait. How this can be solved with dispatch_group_notify ? I have updated my code with dispatch_group_wait. – Govind Apr 03 '17 at 12:06
  • I think I got you wrong. You can not use a return value here, as the method returns before you get the results. You could set a property when things are done (in `resultBlock`) and call another method to handle new results (update UI or such). No `dispatch_group_t` needed. Is this understandable? – shallowThought Apr 03 '17 at 12:14
  • 1
    In other words: you are trying to make an asynchronous method synchronous without waiting, which is not possible. – shallowThought Apr 03 '17 at 12:15
  • Or I wish to move the incremental Store method - (id)executeFetchRequest:(NSFetchRequest*)request withContext:(NSManagedObjectContext*)context error:(NSError**)error - To be executed in other than main thread so that the data processing will not affect the UI – Govind Apr 03 '17 at 12:18
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/139765/discussion-between-igo-and-shallowthought). – Govind Apr 03 '17 at 12:28

1 Answers1

1

This is a skeleton, using a dispatch_group, assuming you are using an NSFetchedResultsController to update your 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
shallowThought
  • 19,212
  • 9
  • 65
  • 112