Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

superclass methods to return subclass type in swift

I have this code:

class Dark: NSObject {
  class var className: String {
    return NSStringFromClass(self)!.componentsSeparatedByString(".").last!
  }

  var success = 0

  class func devour<T: Dark>(params: Int) -> T {
    var s = T()
    return assign(s, params: params)
  }

  class func assign<T: Dark>(item: T, params: Int) -> T{
    if item.dynamicType === self {
      item.success = params
    }
    return item
  }
}

class Black: Dark {
}

class Violet: Dark {
}

Black.className // returns "Black"
Violet.className // returns "Violet"

The problem occurs when I do this:

var ret = Black.devour(5)
ret.success //returns 0 which I expect to be 5

ret.self // returns {Dark success 0} which I expect to be {Black success 0}

The problem here is that when the subclass uses the inherited method devour, it returns an object of type Dark. I want to be able to return the subclass type and not the superclass type when calling devour. Example when I do:

var ret = Black.devour(5)

The class of ret should be of class Black and not of class Dark.

I hope someone can help me on this. Im really out of ideas. Thanks! I want to avoid chaining and I consider it last resort.

like image 550
oregon Avatar asked Mar 05 '15 09:03

oregon


1 Answers

It turns out I was able to do a work around; Thanks to the answer to this question: Cast to typeof(self).

All I need to do is create a method which returns an object of type Self.

first, I created a class that creates an instance of the base class and return it as an instance of AnyObject.

    class func createDark() -> AnyObject {
          var black = Black()
          return black
    }

When I return an instance of Black it automatically casts it into AnyObject since it was the specified return type of the method (I honestly just figured this out and this saved me).

Then I created a helper method that calls createDark() and assigns properties/attributes to the instance:

    class func prepare<T: Dark>(params: Int) -> T{
        var dark = createDark() as T
        dark.assign(params)
        return dark
    }

I used generic type which is of Dark type or its subclass as a return type.

Then I did this:

    class func devour(params: Int) -> Self {
        return prepare(params)
    }

by specifying Self as return type, It automatically casts it to type of self which can be of Dark type or any class that inherits it.

My final code looks like this:

class Dark: NSObject {
    var success = 0

    func assign(params: Int) {
        if self.dynamicType === self { // I dont really have to do this anymore
            self.success = params
        }
    }

    class var className: String {
        return NSStringFromClass(self)!.componentsSeparatedByString(".").last!
    }

    class func createDark() -> AnyObject {
        var black = Black()
        return black
    }

    class func prepare<T: Dark>(params: Int) -> T {
        var dark = createDark() as T
        dark.assign(params)
        return dark
    }

    class func devour(params: Int) -> Self {
        return prepare(params)
    }


}

to check if it solved the problem:

var ret = Black.devour(5)
ret.success //now returns 5 as expected

ret.self // now returns {Black success 0} as expected

works as expected!

like image 156
oregon Avatar answered Oct 30 '22 16:10

oregon