How to make an enum conform to a protocol in Swift?

55,518

Solution 1

This is my attempt:

protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}

enum ExampleEnum : ExampleProtocol {
    case Base, Adjusted

    var simpleDescription: String {
        return self.getDescription()
    }

    func getDescription() -> String {
        switch self {
        case .Base:
            return "A simple description of enum"
        case .Adjusted:
            return "Adjusted description of enum"
        }
    }

    mutating func adjust() {
        self = ExampleEnum.Adjusted
    }
}

var c = ExampleEnum.Base
c.adjust()
let cDescription = c.simpleDescription

Solution 2

Here is my take at it.

As this is an enum and not a class, you have to think different(TM): it is your description that has to change when the "state" of your enum changes (as pointed out by @hu-qiang).

enum SimpleEnumeration: ExampleProtocol {
  case Basic, Adjusted

  var description: String {
    switch self {
    case .Basic:
      return "A simple Enumeration"
    case .Adjusted:
      return "A simple Enumeration [adjusted]"
    }
  }

  mutating func adjust()  {
    self = .Adjusted
  }
}

var c = SimpleEnumeration.Basic
c.description
c.adjust()
c.description

Hope that helps.

Solution 3

Here's another approach, using only the knowledge gained from the tour until that point*

enum SimpleEnumeration: String, ExampleProtocol {
    case Basic = "A simple enumeration", Adjusted = "A simple enumeration (adjusted)"

    var simpleDescription: String {
        get {
            return self.toRaw()
        }
    }

    mutating func adjust() {
        self = .Adjusted
    }
}

var c = SimpleEnumeration.Basic
c.adjust()
let cDescription = c.simpleDescription

If you want to have adjust() act as a toggle (although there's nothing to suggest this is the case), use:

mutating func adjust() {
    switch self {
    case .Basic:
        self = .Adjusted
    default:
        self = .Basic
    }
}

*(Although it doesn't explicitly mention how to specify a return type and a protocol)

Solution 4

Here's a solution that doesn't change the current enum value, but their instance values instead (just in case it is useful to anyone).

enum ProtoEnumeration : ExampleProtocol {
    case One(String)
    case Two(String)

    var simpleDescription: String {
        get {
            switch self {
            case let .One(desc):
                return desc
            case let .Two(desc):
                return desc
            }
        }
    }
    mutating func adjust() {
        switch self {
        case let .One(desc):
            self = .One(desc + ", adjusted 1")
        case let .Two(desc):
            self = .Two(desc + ", adjusted 2")
        }
    }
}

var p = ProtoEnumeration.One("test")
p.simpleDescription
p.adjust()
p.simpleDescription

Solution 5

It is not possible to define variables without getter and setter in enums and therefore it is impossible to have a variable that you can modify.

You can conform to the protocol but you cannot have same behavior with mutating as in classes.

Share:
55,518

Related videos on Youtube

Adrian Harris Crowne
Author by

Adrian Harris Crowne

Updated on June 03, 2020

Comments

  • Adrian Harris Crowne
    Adrian Harris Crowne about 4 years

    Swift documentation says that classes, structs, and enums can all conform to protocols, and I can get to a point where they all conform. But I can't get the enum to behave quite like the class and struct examples:

    protocol ExampleProtocol {
        var simpleDescription: String { get set }
        mutating func adjust()
    }
    
    class SimpleClass: ExampleProtocol {
        var simpleDescription: String = "A very simple class."
        var anotherProperty: Int = 69105
    
        func adjust() {
            simpleDescription += " Now 100% adjusted."
        }
    }
    
    var a = SimpleClass()
    a.adjust()
    let aDescription = a.simpleDescription
    
    struct SimpleStructure: ExampleProtocol {
        var simpleDescription: String = "A simple structure"
    
        mutating func adjust() {
            simpleDescription += " (adjusted)"
        }
    }
    
    var b = SimpleStructure()
    b.adjust()
    let bDescription = b.simpleDescription
    
    enum SimpleEnum: ExampleProtocol {
        case Base
    
        var simpleDescription: String {
            get {
                return "A Simple Enum"
            }
            set {
                newValue
            }
        }
    
        mutating func adjust() {
            self.simpleDescription += ", adjusted"
        }
    }
    
    var c = SimpleEnum.Base
    c.adjust()
    let cDescription = c.simpleDescription
    

    I haven't figured out how to get the simpleDescription to change as a result of calling adjust(). My example obviously won't do that because the getter has a value hard-coded, but how can I set a value for the simpleDescription while still conforming to the ExampleProtocol?

  • Adrian Harris Crowne
    Adrian Harris Crowne about 10 years
    Awesome! I had that idea of creating an adjusted state, but it didn't occur to me that I could change to .Adjusted in the adjust method. Thanks!
  • Admin
    Admin about 10 years
    i agree with your take on the enum itself, and with the code you provided. nice.
  • jpittman
    jpittman about 10 years
    Excellent pointer. Was a bit stuck on this one. One question though: Any reason you added the return value of Void to the adjust function?
  • Angelo
    Angelo about 10 years
    @jpittman because the adjust function returns Void in the ExampleProtocol, it's the same as just using mutating func adjust(). If you want adjust to have a return type, you can change the protocol to: gist.github.com/anjerodesu/e1bf640576a3b6fa415f
  • DiogoNeves
    DiogoNeves about 10 years
    Extra points for whoever finds a way to avoid all those switches. Something along the lines of this fictitious copy self = copy(self, self.desc + ", asdfasdf")
  • Justin Levi Winter
    Justin Levi Winter over 9 years
    I think this approach is probably the best one of the bunch. Quick update is that the simpleDescription should return self.rawValue
  • Ricardo Sanchez-Saez
    Ricardo Sanchez-Saez over 9 years
    This answer is nicer and more succinct than the accepted one.
  • Shaolo
    Shaolo over 9 years
    Just a side note that you can remove the SimpleEnumeration.Adjusted and replace with just ".Adjusted". If the name of the enumeration ever changes then it's one less thing to refactor.
  • Robert
    Robert about 9 years
    Could you also add an explanation?
  • Indra Rusmita
    Indra Rusmita about 9 years
    @Robert it should be self explained like others but the different are that I am using init method in enum and have default basic enum. so you'll see that when you create enum object like in structure and class example in Swift playground.
  • John Doe
    John Doe over 7 years
    Could not edit the answer to correct the syntax error, it is missing a dot, should be case .Base:
  • Arjun Kalidas
    Arjun Kalidas almost 7 years
    Yeah, this is better. Thanks.
  • barry
    barry almost 7 years
    This doesn't conform to the given protocol though