Denis Kim
Denis Kim

Reputation: 1668

Swift 2: How to refer to a type of an element in default implementation of a function in a protocol

I need to get some objects from REST API and map them to local objects using ObjectMapper.

These objects contain a number of enumerations. All of them are coming as integers and I want to map them to locally described enums.

To do that I have to describe standard transform function that is used by ObjectMapper.

    enum Types: Int {
        case Uno  = 1
        case Dos  = 2
        case Tres = 3

        static var transform = TransformOf<Types,Int>(
            fromJSON: {
                $0 != nil
                ? Types(rawValue:$0!)
                : nil
            },
            toJSON: { $0?.rawValue})
    }

The problem is that I have a number of these enumerations and the function is totally same in all of them except that first argument in TransformOf<..> list is specific for each enum.

What I want to do is to create a common protocol with default implementation of that function, something like

protocol Transformable {
var transform: TransformOf<self.Type,Int> {
    get {
        return TransformOf<self.Type,Int>(
                    fromJSON: {
                        $0 != nil
                        ? Types(rawValue:$0!)
                        : nil
                    },
                    toJSON: { $0?.rawValue})
        }
    }
}

...and then to apply the protocol with the implementation to all of the enumerations I have.

Obviously reference of self.Type is not working there and I just can't get how to generally refer to type of specific instance that will finally use the function? Probably I'm thinking wrong way of solving that problem.

Upvotes: 0

Views: 124

Answers (1)

Bell App Lab
Bell App Lab

Reputation: 818

I think what you're missing is the Self identifier. When implementing Generics, the Self keyword acts as a placeholder for the type that implements your protocol. (For more information)

In other words:

protocol Transformable {
    var rawValue: Int { get }
    init?(rawValue: Int)
    func toJSON() -> Int
    static func fromJSON(rawValue: Int) -> Self?
}

Each enum that conforms to the protocol Transformable will then have a static method that returns its own type.

Secondly, since this is Swift 2, you can implement a protocol extension:

extension Transformable {
    func toJSON() -> Int {
        return self.rawValue
    }

    static func fromJSON(rawValue: Int) -> Self? {
        return Self(rawValue: rawValue)
    }
}

Now all enums that conform to the protocol will convert themselves to and from Int:

enum Types: Int, Transformable {
    case Uno = 1
    case Dos = 2
    case Tres = 3
    //No extra implementation
}

enum OtherTypes: Int, Transformable {
    case Cuatro = 4
    case Cinco = 5
    case Seis = 6
    //No extra implementation
}

print(Types.fromJSON(1)!) //prints Uno
print(OtherTypes.fromJSON(4)!) //prints Cuatro
print(Types.fromJSON(4)!) /* throws an error, because the Types enum
                             does not recognise 4 as a raw value */

Upvotes: 1

Related Questions