Un protocollo rappresenta una serie di regole che devono essere rispettate dalla classe che vuole adottarlo. Più precisamente, esso definisce una lista di metodi; una classe che vuole essere conforme a un certo protocollo deve implementare i metodi elencati nel protocollo stesso.
Vediamo come definire un protocollo.
Da Xcode selezioniamo File -> New -> File..., quindi scegliamo Objective-C File e premiamo Next.
Nel pannello che appare digitiamo VehicleProtocol nel campo File. Inoltre. scegliamo Protocol nel campo File Type, e premiamo prima Next e poi Create.
A questo punto Xcode ha creato il protocollo per noi.
#import <Foundation/Foundation.h>
@protocol VehicleProtocol <NSObject>
@end
Siccome concettualmente vogliamo rappresentare un qualche veicolo, aggiungiamo un metodo che avrà senso per ogni veicolo.
#import <Foundation/Foundation.h>
@protocol VehicleProtocol <NSObject>
- (int)numberOfWheels;
@end
A questo punto ogni classe conforme al nostro protocollo VehicleProtocol
dovrà implementare il metodo numberOfWheels
.
Facciamo una prova.
Scegliamo File -> New -> File..., poi selezioniamo Cocoa Class e premiamo Next. Compiliamo il pannello successivo come segue:
- Class: Car
- Subclass of: NSObject
- Language: Objective-C
Infine, premiamo Next e poi Create.
Per rendere la classe Car
conforme a VehicleProtocol
, prima di tutto apriamo il file Car.h e modifichiamolo come segue:
#import <Foundation/Foundation.h>
#import "VehicleProtocol.h"
@interface Car : NSObject<VehicleProtocol>
@end
Ora dobbiamo aggiungere a Car una implementazione del metodo richiesto da VehicleProtocol
. Apriamo Car.m e modifichiamolo come mostrato di seguito:
#import "Car.h"
@implementation Car
-(int) numberOfWheels {
return 4;
}
@end
A questo punto, se apriamo il file main.m possiamo fare un piccolo test. Modifichiamolo come segue:
@import Foundation;
#import "Car.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
id<VehicleProtocol> vehicle = [Car new];
NSLog(@"%d", [vehicle numberOfWheels]);
}
return 0;
}
Abbiamo creato un puntatore (vehicle
) a una classe che deve essere conforme a VehicleProtocol
, e che faremo puntare a un’istanza di Car
.
Nella riga successiva, stiamo chiamando il metodo numberOfWheels
. Infatti, pur non avendo alcuna conoscenza di come potrà essere stato popolato vehicle
, il compilatore sa che l’oggetto referenziato è conforme a VehicleProtocol
, e quindi possiede certamente il metodo numberOfWheels
.
Successivamente possiamo ampliare il nostro esempio creando una seconda classe Bicycle
:
File Bicycle.h
#import <Foundation/Foundation.h>
#import "VehicleProtocol.h"
@interface Bicycle : NSObject<VehicleProtocol>
@end
File Bicycle.m
#import “Bicycle.h"
@implementation Bicycle
- (int)numberOfWheels {
return 2;
}
@end
Ora torniamo a main.m e modifichiamolo come segue:
@import Foundation;
#import "Car.h"
#import "Bicycle.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
id<VehicleProtocol> vehicle = [Car new];
vehicle = [Bicycle new];
NSLog(@"%d", [vehicle numberOfWheels]);
}
return 0;
}
Come si vede, stiamo usando la variabile vehicle
per referenziare prima un oggetto di tipo Car
, e poi un oggetto di tipo Vehicle
. Ancora una volta, l’istruzione NSLog(@"%d", [vehicle numberOfWheels]);
ci assicura che l’oggetto sia dotato del metodo numberOfWheels
.