Search code examples
swiftenumsprotocols

Swift: How to define a required Enum in a Protocol?


Context

Hi, I am working with Protocols and would like to require a specific Enum with predefined cases. However, I get the following Error Message:

Type 'Category' cannot be nested in protocol 'Categorisable'


Code

protocol Categorisable {
    enum Category {}
}

struct Entity: Categorisable {
    enum Category {
        case category1, category2, ...
    }
}

Question

  1. How can I define a required Enum in a Protocol?
  2. Is it possible to also define cases and other default implementations (e.g. computed variables)?

Solution

  • If you just want to share the same enum across all the structs conforming to Categorisable, you can declare the enum outside of the structs, and then declare a typealias in a protocol extension.

    enum DefaultCategory: CategoryProtocol {
        case category1, category2, category3
    
        // computed properties go here...
    }
    
    extension Categorisable {
        typealias Category = DefaultCategory
    }
    

    If some of the conforming structs can have a different enum type in their implementation of the protocol (e.g. with more cases than required), then you should use an associated type. Constrain the associated type to a protocol that specifies the minimum cases you require.

    Here is an example:

    protocol Categorisable {
        associatedtype Category: CategoryProtocol = DefaultCategory
    }
    
    protocol CategoryProtocol {
        static var category1: Self { get }
        static var category2: Self { get }
        static var category3: Self { get }
    
        // computed properties go here...
    }
    
    enum DefaultCategory: CategoryProtocol {
        case category1, category2, category3
    
        // computed properties go here...
    }
    
    // Example of a struct using the default enum
    struct ConformingStruct1: Categorisable {}
    
    // Example of a struct using a custom enum
    struct ConformingStruct2: Categorisable {
        enum Category: CategoryProtocol {
            // with some extra cases
            case category1, category2, category3, category4, category5
    
            // computed properties go here...
        }
    }
    

    Note that conforming structs aren't required to use enums to implement the categories. Conformers could also write a struct or classe, and write static properties to implement them.

    Protocols only specify the interface - on the outside, you can't tell whether Category.category1 is a static readonly property of a class or struct, or an enum case, can you? They all look the same "from the outside". The fact that you know it is implemented as an enum case is an implementation detail, and protocols cannot require that.