Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining a Swift Protocol for Arbitrary, Int-based Enums

I have this enumeration representing a color, and I have added several methods to conveniently obtain new instances based on arithmetic operations on the original's raw value:

enum Color : Int
{
    case Red = 0
    case Green
    case Blue

    case Cyan
    case Magenta
    case Yellow


    static func random() -> Color
    {
        return Color(rawValue: Int(arc4random_uniform(6)))!
    }

    func shifted(by offset:Int) -> Color
    {
        return Color(rawValue: (self.rawValue + offset) % 6)!
        // Cyclic: wraps around
    }
}

(This harks back to the old enums being just int constants)

The problem is, I have several other int-based enums where I would like to introduce similar functionality, but without duplicating code.

I think I should define a protocol extension on RawRepresentable where RawValue == Int:

extension RawRepresentable where RawValue == Int
{

...but that's where my understanding of the syntax ends.

Ideally, I would like to require a static method returning the number of cases, and a provide default implementation of both random() and shifted(_:) above that takes that into account (instead of the hard-coded 6 here).

CONCLUSION: I have accepted the answer by Zoff Dino. Even though the answer given by Rob Napier is exactly what I asked for, it turns out what I was asking for was not the most elegant design after all, and the other answer suggests a better approach. Still, I have upvoted both answers; thanks everyone.

like image 760
Nicolas Miari Avatar asked Nov 07 '15 03:11

Nicolas Miari


People also ask

Can enums implement protocols Swift?

Yes, enums can conform protocols. You can use Swift's own protocols or custom protocols. By using protocols with Enums you can add more capabilities.

Can enum have functions Swift?

Cases as functions Finally, let's take a look at how enum cases relate to functions, and how Swift 5.3 brings a new feature that lets us combine protocols with enums in brand new ways. A really interesting aspect of enum cases with associated values is that they can actually be used directly as functions.

What is Rawvalue in Swift?

Enumerations in Swift are much more flexible, and don't have to provide a value for each case of the enumeration. If a value (known as a raw value) is provided for each enumeration case, the value can be a string, a character, or a value of any integer or floating-point type.

What is enum or enumerations in Swift?

In Swift, an enum (short for enumeration) is a user-defined data type that has a fixed set of related values. We use the enum keyword to create an enum. For example, enum Season { case spring, summer, autumn, winter } Here, Season - name of the enum.


1 Answers

You should extend your custom protocol instead of RawRepresentable. Try this:

protocol MyProtocol {
    static var maxRawValue : Int { get }

    static func random() ->  Self
    func shifted(by offset: Int) -> Self
}

enum Color : Int, MyProtocol
{
    case Red = 0
    case Green
    case Blue

    case Cyan
    case Magenta
    case Yellow

    // The maximum value of your Int enum
    static var maxRawValue: Int {
        return Yellow.rawValue
    }
}

extension MyProtocol where Self: RawRepresentable, Self.RawValue == Int {
    static func random() -> Self {
        let random = Int(arc4random_uniform(UInt32(Self.maxRawValue + 1)))
        return Self(rawValue: random)!
    }

    func shifted(by offset: Int) -> Self {
        return Self(rawValue: (self.rawValue + offset) % (Self.maxRawValue + 1))!
    }
}

let x = Color.random()
let y = x.shifted(by: 1)
like image 107
Code Different Avatar answered Sep 22 '22 13:09

Code Different