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 ?

the_critic
  • 12,720
  • 19
  • 67
  • 115
  • 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)? – Antonio Jul 12 '14 at 09:26
  • superclass does a get class and calls the subclasses dictionary – Daij-Djan Jul 12 '14 at 09:30
  • So you want to enumerate all subclasses from the base class? If yes, I don't think that's possible – Antonio Jul 12 '14 at 09:35
  • Maybe I know what you mean... see my answer below – Antonio Jul 12 '14 at 09:52

3 Answers3

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

Antonio
  • 71,651
  • 11
  • 148
  • 165
  • 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? – AliSoftware Aug 28 '14 at 23:37
  • 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. – Eike Sep 06 '15 at 13:07
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"]
    }
}
Nicolas Buquet
  • 3,880
  • 28
  • 28
-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"
    }
}
Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
  • "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. – user102008 Jul 13 '14 at 04:17
  • It doesn't. But that doesn't mean the function shouldn't exist. – user102008 Jul 13 '14 at 09:08
  • 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. – user102008 Jul 13 '14 at 20:49
  • 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. – user102008 Jul 13 '14 at 20:49