Swift call class function from corresponding subclass in superclass function
Asked Answered
C

3

9

I would like to implement init(coder aDecoder: NSCoder!) in a superclass, and use it in all subclasses by calling a class method on the particular subclass in the superclass at runtime.

MySuperClass

class func dummyDict() -> NSDictionary

init(coder aDecoder: NSCoder!) {

    for(key,value) in self.class.dummyDict(){
                      --------------------
                               ^
                               |
                               |
                 Get this from the corresponding subclass at runtime!

        NSLog("encoding \(value) for key \(key)")
    }

}

Is it possible that subclasses from MySuperClass access the class function dummyDict() at runtime ?

Crosswalk answered 12/7, 2014 at 9:20 Comment(4)
Not sure I caught what you mean - you want that initializer to be called from any subclass, or you want that initializer to call a base method that's overridden in subclasses (and have the correct one invoked)?Deserving
superclass does a get class and calls the subclasses dictionaryBeast
So you want to enumerate all subclasses from the base class? If yes, I don't think that's possibleDeserving
Maybe I know what you mean... see my answer belowDeserving
D
16

I think I caught what you mean. You create a Base class, implementing an initializer and a class (static) function:

class Base {
    class func dummyDict() -> Dictionary<String, String> {
        return ["base1": "val1"]
    }

    init() {
        for (key, value) in self.dynamicType.dummyDict() {
            println("encoding \(value) for key \(key)")
        }
    }
}

Next you want to create subclasses, and have the initializer to call an overridden version of the dummyDict method. You simply have to override that method:

class Subclass1 : Base {
    override class func dummyDict() -> Dictionary<String, String> {
        return ["subclass1": "sub1"]
    }
}

Now, when you create an instance of Subclass1, what's printed is:

encoding sub1 for key subclass1

which is the expected output.

Note the for loop in the initializer is using self.dynamicType.dummyDict() rather than Base.dummyDict(). The latter always calls the class method defined in the Base class, whereas the former calls it in the scope of the actual class inherited from Base

Deserving answered 12/7, 2014 at 9:48 Comment(2)
I was trying to do the same thing but can't make it to work, since the compiler generates an error telling me that I can't use self.dynamicType.dummyDict() as we can't use self inside of an init method ("Use of self in delegating initializer before self.init is called"). Any idea?Boutwell
Hey @AliSoftware, at least in swift 2.0 u can use the dynamicType self.dynamicType.dummyDict() in the init function. Even before init() is called. Otherwise try to call it after init() if that is possible for you.Flitch
C
6

dynamicType is deprecated in Swift 3. We must use type(of:).

So Antonio's example is now:

class Base {
    class func dummyDict() -> [String: String] {
        return ["base1": "val1"]
    }

    init() {
        for (key, value) in type(of: self).dummyDict() {
            print("encoding \(value) for key \(key)")
        }
    }
}

class Subclass1 : Base {
    override class func dummyDict() -> [String: String] {
        return ["subclass1": "sub1"]
    }
}
Coltoncoltsfoot answered 20/10, 2016 at 16:1 Comment(0)
B
-2

[DELETED]

use dynamicType as Antonio suggested in his answer

class Test : NSObject {
    class func dummy() -> String { 
        return "t"
    }

    init() {
        super.init()
        println("\(self.dynamicType.dummy())")
    }
}

class Test1 : Test {
    override class func dummy() -> String  {
        return "t1"
    }
}

class Test2 : Test {
    override class func dummy() -> String  {
        return "t2"
    }
}
Beast answered 12/7, 2014 at 9:34 Comment(4)
"The class() method would return AnyClass! and the Compiler wouldn't know the type at compiler time... " So? The object_getClass() function also returns AnyClass! and that's not a problem.Unqualified
It doesn't. But that doesn't mean the function shouldn't exist.Unqualified
I said object_getClass, not objc_getClass; and the type of the Test class is Test.Type. If you do let cls: Test.Type = object_getClass(self) as Test.Type; println("\(cls.dummy())") in place of your println above, it indeed works.Unqualified
Anyway, when you wrote "self.class is not available in swift AFAICS -- as that would be a major problem for statically typing stuff" which sounds like you're saying the class method isn't available in Swift because its type would somehow be a problem. But I showed that object_getClass does the same thing and also returns AnyClass!, and it is available in Swift and not a problem. That shows that its type is not a problem and they could have made the class method available in Swift; they just didn't, for other reasons.Unqualified

© 2022 - 2024 — McMap. All rights reserved.