Search code examples
iosobjective-ccocoatouchprotocols

Obj-c, can I use a protocol as a type of parameter for function arguments?


I’m create a cocoa touch framework to share some common code between my apps.

I need to pass an instance of a class into a method, which has some specific properties.

The method will be called from the app.

I’m quite new to using protocols.

Should I create a protocol h file in my framework with all the properties required by the function.

If so can I pass the protocol as the type of the instance variable into the function?

If not how can achieve this?


Solution

  • Yes, you can. Here's an example.

    First, declare your protocol in a .h file:

    @protocol Vehicle <NSObject>
    
    @property NSNumber * numberOfWheels;
    
    @required
    -(void)engineOn;
    
    @end
    

    Declare the classes which conform to your protocol:

    #import "Vehicle.h"
    
    @interface Car : NSObject <Vehicle>
    
    @end
    

    Implement the required methods and synthesise the properties:

    @implementation Car
    @synthesize numberOfWheels;
    
    -(void)engineOn {
        NSLog(@"Car engine on");
    }
    
    @end
    

    and another, for the sake of example:

    #import "Vehicle.h"
    
    @interface Motorcycle : NSObject <Vehicle>
    
    @end
    
    @implementation Motorcycle
    @synthesize numberOfWheels;
    
    -(void)engineOn {
        NSLog(@"Motorcycle engine on");
    }
    
    @end
    

    When you declare a method which you want to accept a Vehicle argument, you use the generic id type and specify that any object passed in should conform to Vehicle:

    #import "Vehicle.h"
    
    @interface Race : NSObject
    
    -(void)addVehicleToRace:(id<Vehicle>)vehicle;
    
    @end
    

    Then, in the implementation for that method, you can use the properties and methods declared in the protocol, regardless of the concrete type that has been passed in:

    @implementation Race
    
    -(void)addVehicleToRace:(id<Vehicle>)vehicle {
        [vehicle engineOn];
    }
    
    @end
    

    Then, as you'd expect, you can pass in instances of concrete classes that conform to your protocol:

    Motorcycle *cycle = [[Motorcycle alloc] init];
    cycle.numberOfWheels = 2;
    Car *car = [[Car alloc] init];
    car.numberOfWheels = 4;
    Race *race = [[Race alloc] init];
    [race addVehicleToRace:car];
    [race addVehicleToRace:cycle];
    

    And the appropriate concrete implementation of the protocol's methods will be executed, depending on the actual concrete types that you pass as a parameter:

    2018-10-15 13:53:45.039596+0800 ProtocolExample[78912:1847146] Car engine on
    2018-10-15 13:53:45.039783+0800 ProtocolExample[78912:1847146] Motorcycle engine on