0

I am writing an iPad App in which I load data for a multi-storied building asynchronously. I have set up NSNotifications to alert the user once data-load for all floors is complete.

The data load for each floor is kicked off in a loop when a load button is pressed in ChildViewController (a popup VC)

ChildViewController is launched from ParentViewController.

I add an observer in ChildViewController for a notification named "dataloaded" and set up a handler function childDataLoaded to handle the notification.

Since ChildViewController may be dismissed before the data load is completed I also have a observer and handler (parentDataLoaded) setup in ParentViewController to handle the same "dataloaded" notification.

I have implemented the data load function 'parseAndSaveData' in AppDelegate. parseAndSaveData is invoked when the ChildViewController button is clicked. It takes as parameter the floor identifier (NSString). It calls a web-service to get data for that floor and loads this data into the database. The webservice is quick but adding the data to the sqllite database takes a longer time (I am using Core data). I therefore invoke this dataload part using a dispatch_asynch call (since this is the most time consuming part).

The dataload portion when complete posts the "dataloaded" notification.

I expect this notification to invoke either the handler in ChildViewController or in ParentViewController (whichever is active when the notification is posted)

The problem I have is that the notification is unpredictable and I see only one of the handlers (the one in ChildViewController) getting invoked and it gets invoked for only one of the floors, despite the fact that all floors get loaded successfully.

Any advise on the above design and implementation or alternatives would be most appreciated!

ADDING CODE FOR THE dispatch_group suggestion from @Samuel

Confirm action on my popup VC kicks off the following…
   creates a a GCD dispatch_group, floorDataGroup                    
   creates a GCD dispatch_queue, floorDataQueue, using dispatch_get_global_queue  
   with default priority

   loops over floors in building and for each floor  {
    dispatch_group_async(floorDataGroup, floorDataQueue, ^{  
              // start dispatch_group_async block
      //gets rooms details for the building and floor as follows:
      Calls webservice (using AFNetworking Library) to get room details, 
              which on success executes a block
        ( ^{
              Parses the XML, extracts room data 
                          Inserts room data into Core Data/sqllite table
           }); //end web service success block

    }); //end dispatch_group_async block
} //end loop over each floor

   dispatch_group_notify(floorDataGroup, floorDataQueue, ^{  
       //start dispatch_group_nbotify block
       create alert (UIAlert) with message “All floors loaded” 
       and an OK button to dismiss the alert
    [alert show]
    }
CoolDocMan
  • 637
  • 7
  • 29

1 Answers1

1

I would consider using NSOperationQueue... from Apple GCD Docs

GCD is not restricted to system-level applications, but before you use it for higher-level applications, you should consider whether similar functionality provided in Cocoa (via NSOperation and block objects) would be easier to use or more appropriate for your needs. See Concurrency Programming Guide for more information.

Specifically look at using NSBlockOperation. You can add each request for data in a separate execution block with addExecutionBlock:. Then set your completion block with setCompletionBlock:. Make sure that your completion block is fired on the main thread.

If you must use GCD then I would recommend looking at groups.

stackoverflow related questions with good answers:

Community
  • 1
  • 1
Samuel
  • 401
  • 2
  • 10
  • Thank you Samuel! I will look into implementing this with dispatch_group, as I am sort of vested in GCD at this point. Will keep posting here as I make progress/run into issues. – CoolDocMan Dec 27 '12 at 18:54
  • Hi - here is where I am with using GCD, specifically the dispatch_group_async attempt (one of your suggestions Samuel) – CoolDocMan Jan 03 '13 at 18:57
  • I created the folllowing implementation. In order to make this readable I have provided a mix of code, pseudo-code and explanation ... – CoolDocMan Jan 03 '13 at 22:29
  • ADDED THE CODE/PSEUSO-CODE MIX TO THE POST – CoolDocMan Jan 03 '13 at 23:26
  • THE ISSUE I HAVE IS: When I hit the confirm button, the data load starts in the background as expected. BUT there are two problems: (1) The firing of the Notification happens prematurely, and the UIAlert "All floors loaded" pops up while the data is still being fetched in the background (2) The process instead of actually running in the background appears to be blocking and the UI is frozen. I cannot hit OK on the UIAlert until all floors are processed and loaded in the database (I confirmed this from the log statements I am writing out to the console) – CoolDocMan Jan 03 '13 at 23:27
  • Could it be that the Core Data/SQLLite writes happen on the main thread and therefore block despite the fact that it is enveloped in a GCD dispatch? – CoolDocMan Jan 03 '13 at 23:48
  • [AFNetworking](http://afnetworking.github.com/AFNetworking/) contains subclasses of NSOperation so what you do is create a custom NSOperationQueue and drop all of your AFHTTPRequestOperations or whatever in that queue then you add a listener on that queue to find out when it is empty and when it is... you notify. – Samuel Jan 04 '13 at 03:03
  • What you are doing in your pseudo code there is running something asynchronous that is already asynchronous which is why you are notified too early. I feel your pain my friend! – Samuel Jan 04 '13 at 03:11