web-dev-qa-db-fra.com

Comment exiger qu'une énumération soit définie dans Swift Protocol

Est-il possible qu'un protocole nécessite la définition d'une énumération?

//trying to do this
protocol JSONEncodable {
    enum PropertyName // Type not allowed here
    func valueForProperty(propertyName:PropertyName) -> Any
}

//which would be implemented like this
struct Person : JSONEncodable {
    var firstName : String
    var lastName : String

    enum PropertyName {
        case FirstName
        case LastName
        func allValues() {
            return [Person.PropertyName.FirstName, Person.PropertyName.LastName]
        }
        func stringValue() {
            return "\(self)"
        }
    }
    func valueForProperty(propertyName:PropertyName) -> Any {
        switch propertyName {

        case .FirstName:
            return firstName

        case .LastName:
            return lastName
        }
    }
}

//so that I could do something like this
extension JSONEncodable {

    func JSONObject() -> [String:AnyObject] {
        var dictionary = [String:AnyObject]()
        for propertyName in PropertyName.allValues {
            let value = valueForProperty(propertyName)

            if let valueObject = value as? AnyObject {
                dictionary[propertyName.stringValue()] = valueObject

            }else if let valueObject = value as? JSONEncodable {
                dictionary[propertyName.stringValue()] = valueObject.JSONObject()
            }

        }
        return dictionary
    }
}
16
joels

Ce n'est pas possible dans Swift. Si c'était possible, il est difficile de savoir comment vous l'utiliseriez directement, car vous ne pourriez vous référer à aucun des cas (car vous ne savez pas ce qu'ils sont). Vous devrez éventuellement as transtyper, ce qui brise tout le point du protocole. (On pourrait imaginer des utilisations si enum était un type de collection, mais ce n'est pas le cas, et si c'était le cas, vous pourriez simplement exiger "un type de collection.")

7
Rob Napier

Les protocoles peuvent avoir associatedtypes qui aurait juste besoin d'être respecté dans n'importe quelle sous-classe:

enum MyEnum {
    case foo
    case bar
}

protocol RequiresEnum {
    associatedtype SomeEnumType

    func doSomethingWithEnum(someEnumType: SomeEnumType)
}

class MyRequiresEnum: RequiresEnum {
    typealias SomeEnumType = MyEnum

    func doSomethingWithEnum(someEnumType: SomeEnumType) {
        switch someEnumType {
        case .foo:
            print("foo")
        case .bar:
            print("bar")
        }
    }
}

let mre = MyRequiresEnum()
mre.doSomethingWithEnum(.bar)

Modifier: Le associatedtypedoit être respecté

18
Mackarous

Je pense que vous pouvez le faire avec un associatedtype qui adhère à RawRepresentable

Voici un exemple:

protocol SomeProtocol {
    associatedtype SomeType: RawRepresentable
}

Si vous devez spécifier le type de RawRepresentable comme String par exemple, vous pouvez le faire:

protocol SomeProtocol {
    associatedtype SomeType: RawRepresentable where SomeType.RawValue: StringProtocol
}

Vous aurez maintenant une erreur de compilation si vous essayez d'implémenter le protocole avec autre chose qu'un enum qui a String comme RawRepresentable. J'espère que ça aide.

5
Robin Dorpe