11

I ask a question today because I’m little bit lost today. It’s about Swift and protocol and more about Protocol Oriented Programming (POP).

I read articles about it, even a book but I’m still confused. Everybody seems to say that Protocol is a great tool and so on but I don’t really understand its power.

I’ve a question because I’m coding a class Volume which is the representation of a volume as an object. Let’s say

struct Volume {
  var value: Float = 1
  var isLogScale: Bool = false
  var maxLogVolume: Float = 6.0 // value in dB
  var maxLinearVolume: Float = 1.0
  let dynamicRange: Float = 50.0


  func convertLinearToLog() -> Float {
    // Do some maths
  }

  func otherFunction() {
    print("Hello, I'm the most useless function in the world.")
  }
}

This is a typical class nothing special.

But… Should I better us a protocol like this:

protocol VolumeProtocol {
  var value: Float {get set}
  var isLogScale: Bool {get set}
  var maxLogVolume: Float {get set}
  var maxLinearVolume: Float {get set}
  let dynamicRange: Float {get}

  func convertLinearToLog() -> Float
  func otherFunction()
}

And then re implement everything like

struct MyVolumeClass: VolumeProtocol {
// Same thing as before
}

I don’t really manage to answer to this question, so if you could help me when to use protocol and when not I would appreciate.

DEADBEEF
  • 1,930
  • 2
  • 17
  • 32
  • 1
    You should work with a struct not a class. btw worth watching https://developer.apple.com/videos/play/wwdc2015/408/ – Leo Dabus Sep 29 '17 at 20:53
  • 1
    @LeoDabus you are totally right. Sorry I made a mistake here for the class/struct. Indeed this case is totally a struct. I edited my question. And thanks for the link – DEADBEEF Sep 29 '17 at 20:57
  • 2
    In general one of the possible scenarios for using a protocol is when you want to abstract away some common methods/properties of several classes, but you don't want to use inheritance for any reason (such as your classes need to inherit from another class already). For your current implementation, it would make no sense to create a `VolumeProtocol`, since I don't suppose you would have several different classes conforming to this protocol. – Dávid Pásztor Sep 29 '17 at 21:00
  • @DávidPásztor thanks for the explanation, that's why I had the feeling my case was not good. In fact protocol could be see like a big superclass that we slice into mini-focused one. In fact in my case it could the procotols `volume`, `audioFormat` and classes `singleAudioPlayer` `multipleAudioPlayer` that conform to the previous protocols. It's still not natural for me to do that because writing "protocol" with just declaration still seems useless for me (I only used protocol for delegate pattern) but it helps for the maintenance of the code – DEADBEEF Sep 29 '17 at 21:14
  • 1
    @DEADBEEF you can also define default implementations of functions in protocols, which way the protocol won't be just a declaration – Dávid Pásztor Sep 29 '17 at 23:59

1 Answers1

11

Protocols have more than one use case, but think of it this way:

  • For classes, protocols provide a lightweight inheritance hierarchy separate from the class hierarchy. Given a class Animal and its subclasses Cat, Dog, Bird, and Insect, how would you specify that only Bird and Insect share the fly method?

  • For structs, protocols provide an inheritance hierarchy that would otherwise be missing entirely! A struct has no superstruct. So, given a struct Bird and a struct Insect, how would you specify that they share a fly method?

Now, you could answer that Bird and Insect just happen to have fly methods and that's the end of the story. But that won't do when you need to speak of the set "all types that have a fly method". And you do need to speak of that set when you want the compiler to be able to send the fly method to an object on the grounds that it has a fly method.

The solution is a protocol:

protocol Flier {
    func fly()
}

Now Flier is a type. An instance of any type that conforms to Flier can be used where a Flier is expected, and the compiler will let you tell any Flier to fly, so the problem is solved:

var myFlier : Flier = Bird() // if Bird conforms to Flier
myFlier.fly() // legal
matt
  • 515,959
  • 87
  • 875
  • 1,141