Swift 2 Add Protocol Conformance to Protocols

Swift 2 add protocol conformance to protocols

As the error message says: an extension of a protocol cannot have an inheritance clause. Instead, you could make MyData protocol inherit from Equatable in the original declaration.

protocol MyData: Equatable {
var myDataID: Int { get }
}

You could then extend add an implementation of == for types that conform to MyData:

func == <T: MyData>(lhs: T, rhs: T) -> Bool {
return lhs.myDataID == rhs.myDataID
}

However, I would highly not recommend this! If you add more properties to conforming types, their properties won't be checked for equality. Take the example below:

struct SomeData: MyData {
var myDataID: Int
var myOtherData: String
}

let b1 = SomeData(myDataID: 1, myOtherData: "String1")
let b2 = SomeData(myDataID: 1, myOtherData: "String2")

b1 == b2 // true, although `myOtherData` properties aren't equal.

In the case above you'd need to override == for SomeData for the correct result, thus making the == that accepts MyData redundant.

Make a protocol conform to another protocol

Protocols can inherit each other:

Protocol Inheritance


A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance, but with the option to list multiple inherited protocols, separated by commas:

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// protocol definition goes here
}

So, you basically need to do this:

protocol InstrumentForProfessional {
var title: String {get}
}

protocol Pen: InstrumentForProfessional {
var title: String {get} // You can even drop this requirement, because it's already required by `InstrumentForProfessional`
var color: UIColor {get}
}

Now everything that conforms to Pen conforms to InstrumentForProfessional too.

Swift Protocols: Adding Protocol conformance to an Instance

I propose an alternative approach

You can use a factory method:

class FigureTypeFactory {
static func createFigure(withType type: TypeOfFigure) -> Figure {
switch type {
case .square: return new FigureSquare()
case .circle: return new FigureCircle()
case .triangle: return new FigureTriangle()
}
}
}

class Figure { }

class FigureSquare: Figure, Square { }

Swift: Is it possible to add a protocol extension to a protocol?

It seems there are two use-cases of why you may want to do what you are doing. In the first use-case, Swift will allow you to do what you want, but not very cleanly in the second use-case. I'm guessing you fall into the second category, but I'll go through both.

Extending the functionality of TheirPcol

One reason why you might want to do this is simply to give extra functionality to TheirPcol. Just like the compiler error says, you cannot extend Swift protocols to conform to other protocols. However, you can simply extend TheirPcol.

extension TheirPcol {
func extraFunc() { /* do magic */ }
}

Here, you are giving all objects that conform to TheirPcol the method extraFunc() and giving it a default implementation. This accomplishes the task of extending functionality for the objects conforming to TheirPcol, and if you want it to apply to your own objects as well then you could conform your objects to TheirPcol. In many situations, however, you want to keep MyPcol as your primary protocol and just treat TheirPcol as conforming to MyPcol. Unfortunately, Swift does not currently support protocol extensions declaring conformance to other protocols.

Using TheirPcol objects as if they were MyPcol

In the use case (most likely your use case) where you really do need the separate existence of MyPcol, then as far as I am aware there is no clean way to do what you want yet. Here's a few working but non-ideal solutions:

Wrapper around TheirPcol

One potentially messy approach would be to have a struct or class like the following:

struct TheirPcolWrapper<T: TheirPcol>: MyPcol {
var object: T

func extraFunc() { /* Do magic using object */ }
}

You could theoretically use this struct as an alternative to casting, as in your example, when you need to make an existing object instance conform to MyPcol. Or, if you have functions that accept MyPcol as a generic parameter, you could create equivalent functions that take in TheirPcol, then convert it to TheirPcolWrapper and send it off to the other function taking in MyPcol.

Another thing to note is if you are being passed an object of TheirPcol, then you won't be able to create a TheirPcolWrapper instance without first casting it down to an explicit type. This is due to some generics limitations of Swift. So, an object like this could be an alternative:

struct TheirPcolWrapper: MyPcol {
var object: MyPcol

func extraFunc() { /* Do magic using object */ }
}

This would mean you could create a TheirPcolWrapper instance without knowing the explicit type of the TheirPcol you are given.

For a large project, though, both of these could get messy really fast.

Extending individual objects using a child protocol

Yet another non-ideal solution is to extend each object that you know conforms to TheirPcol and that you know you wish to support. For example, suppose you know that ObjectA and ObjectB conform to TheirPcol. You could create a child protocol of MyPcol and then explicitly declare conformance for both objects, as below:

protocol BridgedToMyPcol: TheirPcol, MyPcol {}

extension BridgedToMyPcol {
func extraFunc() {
// Do magic here, given that the object is guaranteed to conform to TheirPcol
}
}

extension ObjectA: BridgedToMyPcol {}
extension ObjectB: BridgedToMyPcol {}

Unfortunately, this approach breaks down if there are a large number of objects that you wish to support, or if you cannot know ahead of time what the objects will be. It also becomes a problem when you don't know the explicit type of a TheirPcol you are given, although you can use type(of:) to get a metatype.

A note about Swift 4

You should check out Conditional conformances, a proposal accepted for inclusion in Swift 4. Specifically, this proposal outlines the ability to have the following extension:

extension Array: Equatable where Element: Equatable {
static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... }
}

While this is not quite what you are asking, at the bottom you'll find "Alternatives considered", which has a sub-section called "Extending protocols to conform to protocols", which is much more what you're trying to do. It provides the following example:

extension Collection: Equatable where Iterator.Element: Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
// ...
}
}

Then states the following:

This protocol extension would make any Collection of Equatable elements Equatable, which is a powerful feature that could be put to good use. Introducing conditional conformances for protocol extensions would exacerbate the problem of overlapping conformances, because it would be unreasonable to say that the existence of the above protocol extension means that no type that conforms to Collection could declare its own conformance to Equatable, conditional or otherwise.

While I realize you're not asking for the ability to have conditional conformances, this is the closest thing I could find regarding discussion of protocols being extended to conform to other protocols.

Add Swift protocol conformance to Objective-C header and make it public

In pure objective-c, you cannot make a class conform to a protocol without importing it in the header. To make the use of a protocol private, the conformance shouldn't be declared in the header. It remains possible to call such a method using a cast however, but it should be done with caution because it's a little bit unsafe :

if ([anInstance respondToSelector:@selector(myProtocolMethod)])
[(id<MyProtocol>)anInstance myProtocolMethod];

I'm not familiar with Swift, but I think you can do the same this way (or something close to it) :

 if let conformingInstance = anInstance as? MyProtocol
conformingInstance.myProtocolMethod

EDIT : To complete my first assertion, forward declarations can still be used in the header when you need to declare a method receiving or returning an instance conforming to that protocol :

@SomeProtocol;

// This is not possible
@interface MyClass : NSObject <SomeProtocol>

// But this is possible
@property (nonatomic) id<SomeProtocol> someProperty;
-(void) someMethod:(id<SomeProtocol>)object;
@end

In this document Apple clearly said that :

Forward declarations of Swift classes and protocols can be used only
as types for method and property declarations.

So it seems that the rule is the same whatever the protocol is an Objective-c protocol or a Swift protocol.

Conditional Protocol Conformance to Protocol

The reason why this is not allowed is stated here:

This protocol extension would make any Collection of Equatable elements Equatable, which is a powerful feature that could be put to good use. Introducing conditional conformances for protocol extensions would exacerbate the problem of overlapping conformances, because it would be unreasonable to say that the existence of the above protocol extension means that no type that conforms to Collection could declare its own conformance to Equatable, conditional or otherwise.

See also this question.

If you just don't want to write the duplicate implementation of intRepr everytime, you can do this:

struct StringContainer : ShowableAsIntContainer {
typealias T = String
let element: String
}

struct IntContainer : ShowableAsIntContainer {
typealias T = Int
let element: Int
}

extension Container where T : ShowableAsInt {
func intRepr() -> Int {
return element.intRepr()
}
}

typealias ShowableAsIntContainer = ShowableAsInt & Container

Swift class conformance of multiple protocols (XCode 7, iOS 9, Swift 2.1)

You have to implments the protocol function in the class

For example

protocol Protocol_A {
func someFunc()
}

protocol Protocol_B {
func someFuncB()
}

protocol Protocol_C {
}

protocol Protocol_D {
}

class ViewController: UIViewController, Protocol_A, Protocol_B, Protocol_C, Protocol_D {
func someFunc() {

}
func someFuncB() {

}
}

If you want function to be optional

@objc protocol Protocol_A {
optional func someFunc()
}

Conditional protocol conformance?

This was implemented in Swift 4.1.

Swift protocol conformance by extension between frameworks

I've realised this didn't receive any answers, and I've been using this method for a while now, so I thought I should post an answer.

It turns out class extensions are global - if one module extends a class, it is extended for every module by the virtue of that module being present. This is independent of whether the second module is imported, only on it being installed.

So, e.g. if Module A contains class Foo, and Module B extends Foo to conform to some protocol (e.g. Hashable). If Module A then checks for Hashable conformance, it will find that Foo does indeed conform if and only if Module B is also present.

Returning Two Types from one Function using Protocol Conformance

Suppose your method compiles,

Let's create another type that conforms to PriceCalculatable:

struct Foo : PriceCalculatable {}

Now we try to call your method:

let foo: Foo = PriceCalculator.culculateFinalPrice(for: someProducts, applying: myCoupon)

From the compiler's perspective, the above compiles, yet this results in an inconsistency at runtime. How can the runtime convert a Double (finalPrice) into a Foo?

Therefore, your method should not compile.

To make it work, you can create a ConvertileFromDouble protocol and make Int and Double conform to it. In the protocol, you need to specify an initialiser that takes a Double as argument.

protocol ConvertibleFromDouble {
init(_ doubleValue: Double)
}

extension Int: ConvertibleFromDouble {

}

extension Double: ConvertibleFromDouble {

}

class PriceCalculator {
static func culculateFinalPrice<T: ConvertibleFromDouble>(for products: [Product],
applying coupon: Coupon?) -> T {
...


Related Topics



Leave a reply



Submit