Reputation: 7721
Is it possible to have a Protocol require that an enum be defined?
//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
}
}
Upvotes: 41
Views: 34811
Reputation: 77
The other answer here are great. Here's another similar approach enforcing other protocols on the enum as well as variables
protocol MyEnumProtocol: Codable, CaseIterable {
var prettyString: String { get }
}
protocol RequiresEnum {
associatedtype MyEnum: MyEnumProtocol
}
class SampleClassConformingTo: RequiresEnum {
enum MyEnum: MyEnumProtocol {
case foo
case bar
var prettyString: String {
switch self {
case .foo:
return "Foo"
case .bar:
return "Bar"
}
}
}
}
Pretty much the same as the other answers but I think it's a bit more readable defining the associatedtype
protocol
Upvotes: 0
Reputation: 1517
Protocols can have associatedtypes
which would just need to be adhered to in any subclass:
enum MyEnum: String {
case foo
case bar
}
protocol RequiresEnum {
associatedtype SomeEnumType: RawRepresentable where SomeEnumType.RawValue: StringProtocol
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(someEnumType: .bar)
Edit: The associatedtype
must be adhered to
Upvotes: 48
Reputation: 352
I think you can do it with an associatedtype
that adheres to RawRepresentable
Here's an example:
protocol SomeProtocol {
associatedtype SomeType: RawRepresentable
}
If you need to specify the type of RawRepresentable
like String
for example, you can do that:
protocol SomeProtocol {
associatedtype SomeType: RawRepresentable where SomeType.RawValue: StringProtocol
}
Now you'll have a compiler error if you try to implement the protocol with anything else than an enum
that has String
as RawRepresentable
.
I hope it helps.
Upvotes: 22