Wanting to understand how Java/C# interfaces are implemented in objective-c, I created this example based on the one I found here.
1. Create the protocol.
Interfaces in objective-c are called protocols. Here’s a protocol for printing.
Printing.h
#import <Foundation/Foundation.h> @protocol Printing -(void) print; @end @interface Printing : NSObject @end
The protocol or interface (not be be confused with the other interface in this file) defines a single method – print.
2. Implement the protocol.
We’re going to implement this protocol two ways. One with a fraction and another with a complex number.
Fraction.h
#import <Foundation/NSObject.h> #import "Printing.h" @interface Fraction: NSObject <Printing> @property (nonatomic) int numerator; @property (nonatomic) int denominator; -(Fraction*) initWithNumerator: (int) n denominator: (int) d; @end
To say that we implement the protocol we put the protocol in after the objective-c interface definition.
@interface Fraction: NSObject <Printing>
Then we do the actual implementation in the .m file.
Fraction.m
#import "Fraction.h" #import <stdio.h> @implementation Fraction @synthesize numerator = _numerator; @synthesize denominator = _denominator; -(Fraction*) initWithNumerator: (int) n denominator: (int) d { self = [super init]; if ( self ) { self.numerator = n; self.denominator = d; } return self; } -(void) print { printf( "%i/%i", self.numerator, self.denominator ); } @end
Complex.h
#import <Foundation/NSObject.h> #import "Printing.h" @interface Complex: NSObject <Printing> @property (nonatomic) double real; @property (nonatomic) double imaginary; -(Complex*) initWithReal: (double) r andImaginary: (double) i; @end
Complex.m
#import "Complex.h" #import <stdio.h> @implementation Complex @synthesize real = _real; @synthesize imaginary = _imaginary; -(Complex*) initWithReal: (double) r andImaginary: (double) i { self = [super init]; if ( self ) { self.real = r; self.imaginary = i; } return self; } -(void) print { printf( "%_f + %_fi", self.real, self.imaginary ); } @end
3. Test.
Then to use the protocol as a fraction or a complex number we do the following:
SpikeProtocolTests.m
#import "SpikeProtocolTests.h" #import "Fraction.h" #import "Complex.h" @implementation SpikeProtocolTests - (void)testExample { Fraction *frac = [[Fraction alloc] initWithNumerator: 3 denominator: 10]; Complex *comp = [[Complex alloc] initWithReal: 5 andImaginary: 15]; id <Printing> printable; // print it printable = frac; printf( "The fraction is: " ); [printable print]; printf( "\n" ); // print complex printable = comp; printf( "The complex number is: " ); [printable print]; printf( "\n" ); } @end
The magic pretty much happens here:
Fraction *frac = [[Fraction alloc] initWithNumerator: 3 denominator: 10]; Complex *comp = [[Complex alloc] initWithReal: 5 andImaginary: 15]; id <Printing> printable;
We define our objects (which implement the interface) and a variable id that implements the interface. The reason this object is of type id is so we can implement multiple interfaces (id is a reserved object type in objective-c meaning any object).
Then to switch implementations we just change implementations:
printable = frac; printable = comp;
The output should look something like this:
For instructions on how to see the unit test output in Xcode look here.
Zak
Nov 23, 2012 @ 18:44:10
This doesn’t actually explain how the protocol method gets called…where is Printing.m? How does it call “print”?
JR
Nov 27, 2012 @ 16:22:33
Hi Zak. There is no Printing.m file. Only the .h defining the interface.
The implementation happens in Fraction.m and Complex.m who’s header files implement the interface.
So when print is called, it is called on the Fraction.m and Complex.m after they have been cast appropriately.
Cheers
Haykel
Dec 03, 2012 @ 14:37:42
Thank you for this little but useful tuto,
Can i add a property to my protocol, or does it only implement methods ?
JR
Dec 03, 2012 @ 20:18:11
Thanks Haykel. Protocols can have properties. But you need to implement them yourself.
http://stackoverflow.com/questions/844678/how-to-handle-objective-c-protocols-that-contain-properties
viniciusmo
Jan 09, 2013 @ 13:06:49
Best tutorial , thanks 🙂
Sangeetha
Feb 01, 2013 @ 07:37:06
Hi,
It was a nice explanation.
Could you explain
-(Fraction*) initWithNumerator: (int) n denominator: (int) d;
and in implementation self = [super init];
Kevin
Mar 11, 2013 @ 08:47:54
I’m left wondering what practical benefit @protocol is to the programmer? We haven’t written less code – in fact we’ve written quite a bit more – and I’m not seeing any real polymorphism benefits for my effort. Am I missing something?
JR
Mar 11, 2013 @ 12:11:24
I don’t think so Kevin. The reason why it’s important to understand protocols is because they are so extensively used in Objective-C. You don’t need to write them yourself, but I would recommend understanding them from an API point-of-view.
Good question. Thanks for asking.
Kevin
Mar 12, 2013 @ 21:59:58
Much appreciated!