Introduction
A common problem in Object Oriented programming systems is how to pass data between Objects asynchronously. If your system is simple and procedural, communication is easy, the Parent Object can pass data to the Child Object as arguments and the Child returns the result. A simple method call will suffice. Things are not so straightforward if the objects are running asynchronously on separate threads and you want to pass data between them. Lets say you want to update your User Interface with the status of some task running in another object. This post looks at some of the ways to solve this problem in .NET C# and Objective C.
First we will look at asynchronous communication from the Child Object to the Parent Object, since this the most common use case. Data exchange from Parent to Child can usually be accomplished procedurally (via a method call on the Child Object) since generally you have a some UI Event or Parent Object Event which spawns the start of some background process.
Definitions and Example Scenario
Let’s think of the problem in terms of a Parent and Child object. By Parent Object I mean any object that instantiates another object called the Child Object. A good example of a Parent is the UI Object - an instance of UIViewController
in Objective C or WindowsForm
in .NET C#. A child object is any object that is instantiated in the ViewController or Form.
Let’s assume that the parent is a text box, and the child is a class that is communicating with a autonomous Robot. Let’s assume that the Robot sends us a message every 1 second about its whereabouts (over the internet or some other technology). We can easily simulate this Robot by having a periodic timer run in the Child class that spits out some data every 1s. I’ve chosen a timer for simplicity, it could very well be another thread. Our problem is how to display the information the Robot sends us on the UI (and have the user control the Robot).
Traditional Solution in C
If you were programming in C, this problem could be solved by using Callback methods. Callbacks are the standard pattern in event-driven Embedded Systems to pass data from lower layers into application layers. The UI file would define a method that would be called by the Child thread when it receives a message from the Robot. The disadvantage here is that we have ended up tightly coupling the UI with the Robot communication. If we change the UI and don’t want to display the message anymore, we’ll have to modify the Robot communication implementation to not trigger the callback anymore.
To make the implementation more flexible, you can use a higher level of indirection via function pointers. Instead of having a fixed callback function, define a callback function pointer or better yet a table of function pointers. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
The advantage here is that CallBackMethod1 could be deleted later on a UI change, and all you have to do is change the CallBackMethod1 entry to NULL. Also with an Array of callbacks, you can send the data to multiple application modules, say the UI module and a filtering module and so on.
Object Oriented Solution
The solution in Object Oriented languages is similar to that of C, in that it makes use of function (“method” to be more exact) pointers, but is much more powerful and easier to implement. At the heart of it is a thing called “Delegate”.
Delegates in C-Sharp
In C# a delegate
is a build-in reference type, just like class
, string
and others. It specifically indicates a reference to a (surprise, surprise) method (or function in C). So it is nothing but a “Function Pointer Type” with some cool features that we will see soon. It can be used to declare any (static or instance) method - with any return value and any number of parameters.
Coming back to the Robot example, what we need to do is create a property with delegete
type in the Robot Class. Parent classes that wish to be notified on the reception of a message, must assign specific methods to this property. In the Robot Class we just call all the methods assigned to this property when we receive some data that other classes may be interested in.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
There’s a lot more you can do with delegates in C# - you can obviously assign and remove delegates at run-time, the methods assigned to a delegate may be static or an instance methods; if at the parent side you do not wish to go through the trouble of defining a method you can use an Anonymous Delegate - which is a lambda expression containing the code you want to execute in the delegate.
1 2 3 4 5 6 7 8 |
|
If a delegate declaration specifies a return type and multiple methods are added to a delegate instance (multicast delegate), an invocation of the delegate instance returns the return value of the last method referenced. The return values of the other methods cannot be retrieved (unless explicitly stored somewhere in addition to being returned).
Delegates can be invoked from a class that did not declare the delegate. This may seem unnecessary but is important when you are inheriting a class from another, this allows the child class to trigger the delegate if required.
Events in C-Sharp
An Event is also a delegate, but it is restricted that it can only be called (triggered) from the class where it is declared, so inheriting subclasses cannot be trigger an event. You can work around this by declaring a protected method in the base class containing the trigger, that is invoked by the child class.
Also the .NET framework imposes some more restrictions on the delegate types that can be used as Events - they should “take two parameters, an “object source” parameter indicating the source of the event, and an “e” parameter that encapsulates any additional information about the event. The type of the “e” parameter should derive from the EventArgs class. For events that do not pass any additional information, the .NET Framework has already defined an appropriate delegate type: EventHandler
.”
In other words it’s simpler to use events if you don’t have any data to pass, else just use delegates.
Synchronous and Asynchronous delegates
All the delegates we have seen so far are synchronous delegates. i.e. they are invoked synchronously by the callee object. The Robot object must wait for the execution of the delegates to finish before it can continue processing the next message. There may be situations where you want to do an asynchronous call on the delegates, C# has a couple of different ways for implementing this, some more equal than others. From .NET framework 4.0 and above you should use the Task Parallel Library (TPL) for such tasks. It provides a clean and feature rich interface quite similar in functionality to the Grand Central Dispatch (GCD) in Cocoa that we will see later. Using TPL APIs you can queue lambda functions or any delegates for execution at a later point of time. You can also easily receive a return value from this delegate.
The syntax to schedule a callback to be executed asynchronously on one of the system thread pools is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
If for some reason you cannot use TPL, then you can use BeginInvoke to achieve the same result; except that it’s a very ugly and messy way of going about it. Once upon a time, it was the only option though so I’ve described next it since I had gone thtough the trouble of figuring it out. Please skip it if you can :)
(Optional) Asynhronous delegates using BeginInvoke (Obsolete, use TPL if you can)
the BeginInvoke
method (defined in the CLR for each delegate type) is used for this. Note that this is only applicable for delegates that have only one assigned target method.
When calling BeginInvoke on the delegate, you pass the delegate parameters + two additional parameters. One of them is a callback method which - if it exists - will be executed after the asynchronous method executes. The second is state information that can be passed to the callback, it can be any object. Once a BeginInvoke
call is executed, the delegate will be executed on a new thread from the thread pool. BeginInvoke
will also return an object implementing the IAsyncResult
interface which contains information about the current state of the execution of the delegate method. Then the code execution continues.
How do you know that the delegate has completed execution? You have to use EndInvoke
on the delegate. For every BeginInvoke
there must be a corresponding EndInvoke
. You have to pass the IAsyncResult
object returned by BeginInvoke
to it and any other ref
or out
parameters you expect to get back from the asynchronous delegate. Note that the call to EndInvoke
is blocking, and only returns when the async operation has ended or an exception is generated.
This gives you 3 ways to get the result from the asynchronous call -
- Wait-till-done
Just call the
EndInvoke
once you have completed doing your tasks, and wait till the async operation completes.
1 2 3 4 5 6 |
|
- Polling method
Poll the property
AsyncResult.IsCompleted
to know if the async operation has completed or not.
1 2 3 4 5 6 |
|
- Callback method
This presents the cleanest Async pattern in that there is no waiting involved - you pass a callback to be invoked when the Async operation completes, and call
EndInvoke
from within this callback. You can also pass an arbitrary object to the callback method via the state parameter. The callback must be of typeAsyncCallback
.
1 2 |
|
(Optional) Redesign using Task based Asynchronous Pattern (TAP)
The use of TPL and async/await
keyword suggests a redesign of the system based on the Task Based Asynchronous Pattern. What it means that instead of thinking in terms of callbacks, you can actually write your code as if you were dealing with a synchronous system while still not stalling any of the tasks. So you can write the code as if you were polling the Robot for any new data while not starving the parent object. Note that this is only supported from .NET 4.5, and therefore cannot run on a Windows XP system.
For example you could write something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Note how the design is simplified as we don’t have to keep track of any delegate pointers and the flow of the program is very obvious. In practice of course, everything after the await
keyword will be executed asynchronously just as if it were a delegate.
Example Project for C
A Visual Studio project illustrating the above concepts simulating the Robot is here It includes code illustrating all of the above approaches.
Delegates in Objective - C
Objective-C uses delegates extensively to implement the callback pattern, just as C#. However there are some differences in the implementation and some more bells and whistles. So in Objective-C a delegate is NOT a function pointer; but rather an object pointer that points to the object that implements the callback (delegate) methods. Obj-C defines a keyword called protocol
which can be used to declare the callback functions that a delegate to a class must implement. By default these functions are mandatory, meaning that all objects that want to be a delegate of a particular class must implement all the callback functions that the class expects. Optional functions must be declared using the optional
keyword.
For our example, we have a View Controller class that is the parent and wishes to be the delegate of the RobotSim class. RobotSim class will call the View Controller’s implementation of the protocol.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
That’s all there is to it. An interesting corollary of the delegate being an object pointer is that, the delegate class can cheat and call any function defined in the parent class if required (even if it’s not part of the protocol), and can also use this reference to access public properties of the parent class.
So this is an example of a “Synchronous delegate”. The callback will execute in the delegate object’s context, and it’s a blocking call as far as the delegate thread is concerned.
Asynchronous delegates using the Grand Central Dispatch (GCD)
Apple has made it really easy to live asynchronously with the GCD. To execute a function asynchronously, all you need to do is to pass it as a block to a GCD queue, and the framework takes care of almost everything else. If you want to be notified when the function has finished executing, there’s a GCD API for that too. Though there’s a lot to be said about GCD, we will just concentrate on what necessary to implement Asynchronous callbacks.
Steps to execute an asynchronous method are:
-
Make a Queue At some point in your application create a separate queue for the method to run, so that you don’t block the main thread. Or you can use one of the “Global Queues” via
dispatch_get_global_queue()
. Creating a custom queue is good if you want to run code you push onto it serially, FIFO order (not LIFO). If you use one of the global queues, then code runs concurrently and there is no guarantee that the block you pushed onto it first will execute first. The main (UI) queue can be accessed by callingdispatch_get_main_queue()
, but you are generally better off not using it. -
Pass the method to the Queue To execute the callback asynchronously, just use
dispatch_async()
, and pass it the Queue and Callback you want to execute.
1 2 3 4 5 6 7 8 9 10 11 |
|
- Call the completion handler If you want to be notified asynchronously of when the delegate has finished processing the data, then you simply have to call the completion block after you executed the call on the delegate. it’s better to use the global queue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
And that’s all there’s to it!!
A minor note: if your delegate happens to be running on the main thread, AND you only have one parameter to pass via the delegate AND it does not return anything; then a simpler alternative without using GCD is to call performSelectorOnMainThread:
Delegate pointers and ARC / Garbage Collection
In the Objective-C example above, you might have noticed that the delegate property was declared as a weak
reference. This is important as the Automatic Reference Counting scheme of memory management employed by Objective-C cannot figure out circular references. What has happened here is that the ViewController object holds a reference to RobotSim via the property myRobot
, and myRobot
in-turn holds a reference to ViewController
via it’s delegate
property, thus setting ViewController
s retain count to 2. So when you or the system tries to deallocate the ViewController
object, it won’t work because it’s reference count is non-zero (1). If you declare the delegate as a weak
reference, then the compiler will take care that the ViewController
s retain count will not be incremented when you do myRobot.delegate = self;
.
For C#, since the CLR does not use ARC but something called mark and sweep garbage collection which is able to release circular references, so you don’t need to do anything special.
Example Objective C Project
Since the iPhone comes built-in with a lot of nice sensors, we will use this data to replace the hypothetical Robot. To Illustrate delegates, I’ve chosen to read the accelerometer + magnetometer + gyro data available from the Core Motion framework. And to demonstrate Asynchronous delegates, I’ve chosen to read data from the GPS via the Core Location framework.
There’s a class called RobotSim
which reads the accelerometer, gyro and magnetometer data every 0.5s via a timer. This data is passed on to the ViewController using a synchronous delegate. The GPS location data is posted asynchronously using the Grand Central Dispatch methods described above. The project can be downloaded here.