Reputation: 619
In Objective-C, a function is able to return instances of a private type that implements a public class and public protocol without ever defining a public class that conforms to that protocol.
E.g. Let's say I have this header file:
@protocol Flyer <NSObject>
-(void) fly;
@end
@interface Animal : NSObject
-(void) eat;
@end
Animal<Flyer> * randomFlyingAnimal();
And this implementation file:
@implementation Animal
-(void) eat {
NSLog(@"I'm eating");
}
@end
@interface Bird : Animal<Flyer>
@end
@implementation Bird
-(void) fly {
NSLog(@"I'm a flying bird");
}
@end
@interface Bat : Animal<Flyer>
@end
@implementation Bat
-(void) fly {
NSLog(@"I'm a flying bat");
}
@end
Animal<Flyer> * randomFlyingAnimal() {
switch (arc4random() % 2) {
case 0:
return [[Bird alloc] init];
case 1:
default:
return [[Bat alloc] init];
}
}
In this example, the consumer of my code never actually knows about the Bird
class or Bat
class (or any other type that implements Animal
and conforms to Flyer
), but can be sure that the object that's returned from randomFlyingAnimal
can both eat
and fly
.
Is such a thing possible in Swift?
Upvotes: 1
Views: 304
Reputation: 19106
There a a few approaches which you could apply in Swift, but you would probably define a protocol AnimalType
and a protocol FlyerType
- which do not have a relation to each other:
public protocol AnimalType {}
public protocol FlyerType {
func fly()
}
Then, create internal or private classes as follows:
internal class Animal: AnimalType {}
internal class Bird: Animal {}
internal class Bat: Animal {}
Now, class Bird
and Bat
conforms to AnimalType
through inheriting form its base class Animal
. In order to conform to FlyerType
as well we could extend these classes as follows:
extension Bird: FlyerType {
internal func fly() { print("Bird's flying") }
}
extension Bat: FlyerType {
internal func fly() { print("Bat's flying") }
}
Your factory function could then be implemented as below:
public func randomFlyingAnimal() -> protocol<AnimalType, FlyerType> {
switch (arc4random() % 2) {
case 0: return Bird()
default: return Bat()
}
}
protocol<AnimalType, FlyerType>
is a protocol composition type - whose application seems useful in this case.
Upvotes: 0