Nuno Dias
Nuno Dias

Reputation: 3948

Why does an override method defined in a protocol get called in the parent class and not it's subclass?

I have a protocol:

public protocol JSONMapper {
    func map(fromJSON json:JSON) -> Self
}

And a class Model, that all my model objects inherit from:

class Model: JSONMapper {

    func map(fromJSON json: JSON) -> Self {
        return self
    }

    class func instances (fromJSON json:[JSON]) -> [AnyObject] {
        var objects = [Model]()
        for item in json {
            objects.append( Model().map(fromJSON: item) )
        }
        return objects
    }

}

An example would be:

class Workout: Model {

    var uniqueID: String?

    override func map(fromJSON json: JSON) -> Self {
        if let value = json["UniqueID"].string { self.uniqueID = value }
        return self

    }

}

From the above, I would expect this function

fun map(fromJSON json:JSON) -> Self

...to be called from the "Workout" class, when doing this:

if let workouts = Workout.instances(fromJSON: items.arrayValue) as? [Workout] {
    self.workouts = workouts
}

But it doesn't. The function that is called is the one from the parent, defined in the "Model" class.

I also tried to explicitly conform the "Workout" class to the JSONMapper protocol, without success.

Thank you!

EDIT:

A Playground example of the issue above:

import Foundation

public protocol JSONMapper {
    func map(fromJSON json:AnyObject) -> Self
}

class Model: JSONMapper {

    func map(fromJSON json: AnyObject) -> Self {
        println(" model: \(self)") // Outputs: " model: __lldb_expr_83.Model"
        return self
    }

    class func instances (fromJSON json:[AnyObject]) -> [AnyObject] {
        var objects = [AnyObject]()
        for item in json {
            objects.append( Model().map(fromJSON: item) )
        }
        return objects
    }

}

class Workout: Model, JSONMapper {

    var uniqueID: String?

    override func map(fromJSON json: AnyObject) -> Self {
        println(" model: \(self)")
        return self

    }

}

Workout.instances(fromJSON: [""]) // outputs: [__lldb_expr_83.Model]

Upvotes: 2

Views: 332

Answers (1)

Ivica M.
Ivica M.

Reputation: 4823

You are explicitly calling the initializer of 'Model' class inside the 'instances' class method. You should use 'self' instead, but for that to work, a required initializer must exist. Something like this:

class Model: JSONMapper {

    required init() {

    }

    func map(fromJSON json: AnyObject) -> Self {
        println(" model: \(self)")
        return self
    }

    class func instances (fromJSON json:[AnyObject]) -> [AnyObject] {
        var objects = [AnyObject]()
        for item in json {
            objects.append( self().map(fromJSON: item) )
        }
        return objects
    }

}

Upvotes: 2

Related Questions