If you’re new to iOS protocols and delegates, here are the short definitions:
Protocols are a loose contract Interfaces, where methods are declared as required or optional. A class that implement a protocol must implement only required methods.
From the Xamarin documentation: iOS uses Objective-C delegates to implement the delegation pattern, in which one object passes work off to another. The object doing the work is the delegate of the first object. An object tells its delegate to do work by sending it messages after certain things happen. Sending a message like this in Objective-C is functionally equivalent to calling a method in C#. A delegate implements methods in response to these calls, and so provides functionality to the application. Applications in iOS often use delegates when one class calls back to another after an important action occurs.
Let’s see how this work in Xamarin with an example based on the UIPickerView.
Let’s start with a very simple app:
First step is easy, just grab the UIPickerView from the Toolbox and drag it to the storyboard. But then, where we can set the content (i.e. colors list) and how we get selected element?
Short answer, iOS uses Objective-C protocols and delegates to implement the delegation pattern, in which one object passes work off to another.
So we need to implement two protocols: UIPickerViewDataSource and UIPickerViewDelegate.
The first one contains methods that return the number of components and the number of elements of each component, because the picker can contain more than one component:
The second one contain methods that return the content of those components, plus a callback method that receive the message sent by the picker whenever the user select an element of a component.
When the Picker wants to know how many components is made of, it will send a message to an object that implement the UIPickerViewDataSource protocol.
When the Picker needs to render the elements of components (can be a string, an attributeTitle or even a UIView) it will ask that info to another object that implement the UIPickerViewDelegate protocol.
Finally, when the user selects an element, the Picker will send a message (“pickerView:didSelectRow:inComponent:”) to the same object that implement the UIPickerViewDelegate protocol.
To bind those class instances to the Picker instance we have two Picker properties whose names, you guess what, are: DataSource and Delegate.
There is not one way to implement those protocols. In iOS, with Objective-C, you can:
- Create two classes, one per protocol and assign the instances to the DataSource and Delegate properties of the Picker.
- Create a single class that implements both protocols and assign the instance of that class to both DataSource and Delegate properties of the Picker.
- Implement those protocols directly on the ViewController ad set both DataSource and Delegate properties to self.
Moving from Objective-C to C#, in Xamarin protocols has been implemented in classes with abstract and virtual methods. Abstract methods map the required methods of the protocol, while virtual methods map the optional methods of the protocol. The Delegate callback mechanism has been easily implemented with C# events.
Let’s see how we can implement the above three scenarios in Xamarin:
Create two classes, one per protocol
First create the two classes:
And then set the Picker properties:
Where colors contains a list of string:
Create a single class that implements both protocols
With C# we cannot create a class that derives from two base classes (i.e. MyClass: UIPickerViewDataSource, UIPickerViewDelegate is not allowed), because C# does not implement multiple inheritance.
Xamarin solve the problem with a Model class that group together the DataSource and Delegate classes.
So we can create a single class that derive from the UIPickerViewModel class:
Then we can set the Model property of the Picker:
Implement both protocols directly on the ViewController
Looking at the previous solutions, we can see that on first case we injected the reference to the colors property and in the second one we injected the reference to ViewController, because we need those references inside the implementation of the protocols methods.
The easiest thing to do, in this case, is to implement the DataSource and Delegate methods directly in the ViewController using the [Export …] method decoration:
And then set the Picker properties:
Where we used the WeakDelegate property, that accept any NSObject, instead of the Delegate property, that require a UIPickerViewDelegate.
One last note: If we use the technique of method decoration inside the ViewController then we have to deal with Xamarin implementation of iOS native types, like NSAttributeString, while using the Model approach we can use more familiar types, like string.
That’s all folks, happy coding!