Jake T.
Jake T.

Reputation: 4378

If I subclass a class, can I specify a certain subclass an instance variable should be?

I have an NSObject subclass, BaseClass. BaseClass is a placeholder class for a couple subclasses, SubClassA and SubClassB. There is an instance variable that I have present on both of the subclasses. They're the same name, and are both of a corresponding subclass of another object. They're often used in very similar ways, so I wanted to move some functionality from my SubClassA and SubClassB to the BaseClass. However, I need access to that variable.

If I move the variable into the BaseClass, I am unable to specify the proper subclass of it in SubClassA and SubClassB, saying I can't override it. If I use the common parent class of this instance variable in the BaseClass, I lose some access to things that aren't common between how SubClassA and SubClassB work.

This is a more primitive example, but the basics of what I'm trying to do. This example obviously does not work. Are my only options to choose having to define common functionality within SubClassA and SubClassB or is there a proper way to achieve my goal here?

class BaseClass: NSObject {
    var myObject: MyObject
}

class SubClassA: BaseClass {
    override var myObject: MyObjectA
}

class SubClassB: BaseClass {
    override var myObject: MyObjectB
}

class MyObject: NSObject { }

class MyObjectA: MyObject { }

class MyObjectB: MyObject { }

This gives me the error:

Property 'myObject' with type 'MyObjectA' cannot override a property with type 'MyObject'

Upvotes: 3

Views: 68

Answers (3)

RLoniello
RLoniello

Reputation: 2329

You can create a class function in your BaseClass that returns a class that inherits from a BaseObject (myObject) and override it for whichever class you need.

class BaseClassObject: NSObject {

}

class BaseClass: NSObject {
    func generateClass() -> NSObject {
        return BaseClassObject()
    }
}

class BranchedObject: BaseClassObject {

}

class SubClassA: BaseClass {

    var myObject: NSObject?

    override func generateClass() -> NSObject {
        return BranchedObject()
    }

    override init() {
        super.init()
        self.myObject = self.generateClass()
    }

}

Upvotes: 0

tarleb
tarleb

Reputation: 22689

Instead of putting the myObject related code into BaseClass, you could put it into a protocol extension. Consider this:

class BaseClass {
}

class SubClassA: BaseClass, HasMyObject {
    var myObject: MyObjectA
}

class SubClassB: BaseClass {
    var myObject: MyObjectB
}

class MyObject { }

class MyObjectA: MyObject { }

class MyObjectB: MyObject { }

protocol HasMyObject {
    associatedtype MyObjectClass

    var myObject: MyObjectClass { get set }
}

This is conceptually very similar to using generics, but would separate your myObject related code from the rest of the code in your class. Whether this is actually preferable over generics depends on your coding style and specific use-cases.

Upvotes: 2

ukim
ukim

Reputation: 2477

How about using generic? For simplicity, I removed NSObject

class MyObject {

}

class MyObjectA: MyObject {

}

class MyObjectB: MyObject {

}

class BaseClass<T> where T : MyObject {
    var myObject: T?
}

class SubClassA: BaseClass<MyObjectA> {
}

class SubClassB: BaseClass<MyObjectB> {
}

Upvotes: 4

Related Questions