Thursday, April 12, 2012

Implement multi threaded / asynchronous delegate calls

When implementing own classes with a delegate protocol it is very simple to achieve an asynchronous behaviour. To explain how it works ill describe a simple scenario:

You have a class that searches big amount of text for keywords. This class should have a delegate protocol that calls following methods:

//this function is called whenever the class finds a string in the text and delivers an array containing page number, line and text excerpt
-(void)didFindTextOnPage:(NSArray*)arrData;
//function is called when search has finished
-(void)didFinishSearching;

When these methods are called in a different thread, on the main thread e.g. a UITableView could be continuously populated with the search results and a loader could be shown to notify the user that the search is still active. When the search is finished the loader can be removed.

All this is easily achieved with following snippet:

------------------------------------------------------------------


//start different thread
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
   
   //do something in a different thread
   dispatch_async( dispatch_get_main_queue(), ^{
       //thread has finished so call final method
   });
});

------------------------------------------------------------------

In the first line we start a new thread. Everything within this "loop" wont affect the main thread.
dispatch_async... is the callback that is called when the "loop" has finished his operations.

In our search example the above code could be used as follows to have a multithreaded approach:

------------------------------------------------------------------

//start different thread
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                
    //loop over pages
   for(int i = 0; i < [pages count]; i++){

      NSArray* arrLines = [NSDicionary objectAtIndex:i];

      //loop over lines
      for(int j = 0; j < [arrLines count]; j++){

         NSArray* arrLine = [arrLines objectAtIndex:j];

         //if keyword exists
         if([self keyWordExistsOnPage:i forLine:j] == YES){

            //call the delegate method
            [self.delegate didFindTextOnPage: arrLine];
         }
      }
    }

   //callback for thread
   dispatch_async( dispatch_get_main_queue(), ^{
      //thread has finished so call final method
      [self.delegate didFinishSearching];
   });
});


------------------------------------------------------------------

Hope this helps. Let me know in the comments if something could be improved here or if you have another approach.


Happy coding :)

5 comments:

  1. What are you talking about? Delegate method invocations from Cocoa are absolutely not multi-threaded - they all happen on the main thread. Please check your facts before posting tutorials.

    ReplyDelete
  2. Thanks for pointing me at this. I dont know why I had in mind that they are all multi-threaded. I corrected that.

    Besides of that something else you think could be improved? :)

    Cheers

    ReplyDelete
  3. Aren't your calls to didFindTextOnPage: still on the worker thread and not the main thread?

    [self.delegate didFindTextOnPage: arrLine];

    ReplyDelete
  4. I am happy to see the post here.

    ReplyDelete
  5. just checked and it seems like http://www.meetingle.com

    ReplyDelete