user3379127
user3379127

Reputation: 271

Protocol extension vs class extension in Swift

Assume there is a protocol Draggable, usually will be conformed by an UIView object

protocol Draggable {
  drag()
}

We can either implement drag() in a protocol extension as option 1

// option 1
extension Draggable where Self: UIView {
  func drag() {
    // implementation
  }
}
extension UIView: Draggable {} // added after @Rich Tolley's answer

Or we can implement drag() in a UIView extension as option 2

// option 2
extension UIView: Draggable {
  func drag() {
    // implementation
  }
}

Here is my question:

And idea would be helpful.

Upvotes: 19

Views: 3251

Answers (2)

Rich Tolley
Rich Tolley

Reputation: 3842

Yes, there is a difference: (EDIT: or at least there was in the original version of this q, which didn't add extension UIView : Draggable {} to the end of option 1).

  • Option 1 creates a default implementation for instances of UIView that conform to Draggable. You still need to mark UIViews you wish to conform to Draggable as such in the declaration: class MyView : Draggable. Anything that conforms to Draggable but is not a UIView subclass will need to supply its own implementation.

  • Option 2 extends all UIViews to make them conform to Draggable. Nothing else can be a Draggable unless separate extensions are also written for those classes, or they are manually conformed to the protocol. There is no need to add Draggable in the class declaration.

The protocol extension is usually the better option. In this case this is obviously true since not all UIViews can be Draggable. Also, going down the protocol extension route means that you can create a Draggable object that is not a UIView subclass, if necessary (admittedly fairly unlikely, since most Cocoa controls are UIView subclasses - although not all -UIBarButtonItem isn't, strangely)

If you follow option 2, you will be adding unnecessary methods to UIView in a lot of cases, which is a violation of good object oriented design - specifically the Interface Segregation Principle (clients should not be forced to rely on methods they don't use ) - which is the 'I' in the SOLID principles

Upvotes: 9

Palle
Palle

Reputation: 12109

A protocol extension should be used when you want to implement functionality for more than just one class. In this case you should use the extension UIView: Draggable as the Implementation is specific to the UIView class.

Assuming you have a protocol which provides location:

protocol Location {
    var location: CGPoint { get set }
}

and you want every class which implements Location to conform to Draggable, then a protocol extension could be used:

extension Draggable where Self: Location {
    func drag() {
    }
}

For further reference, you should have a look at Protocol-Oriented Programming in Swift from the 2015 WWDC.

Upvotes: 3

Related Questions