Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • Is there a difference between these two approaches (option 1 & option 2) ?
  • If yes, what's the difference and how to choose when we design a our project or library ?

And idea would be helpful.

like image 481
user3379127 Avatar asked Feb 21 '16 09:02

user3379127


People also ask

What is the difference between an extension and a protocol extension?

Protocols let you describe what methods something should have, but don't provide the code inside. Extensions let you provide the code inside your methods, but only affect one data type – you can't add the method to lots of types at the same time.

What is difference between protocol and class Swift?

You can create objects from classes, whereas protocols are just type definitions. Try to think of protocols as being abstract definitions, whereas classes and structs are real things you can create.

What is the use of protocol extension in Swift?

In Swift, you can even extend a protocol to provide implementations of its requirements or add additional functionality that conforming types can take advantage of. For more details, see Protocol Extensions. Extensions can add new functionality to a type, but they can't override existing functionality.

What is a class extension Swift?

Swift Class Extensions Another way to add new functionality to a Swift class is to use an extension. Extensions can be used to add features such as methods, initializers, computed properties and subscripts to an existing class without the need to create and reference a subclass.


2 Answers

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

like image 52
Rich Tolley Avatar answered Dec 04 '22 20:12

Rich Tolley


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.

like image 31
Palle Avatar answered Dec 04 '22 19:12

Palle