If I subclass a class, can I specify a certain subclass an instance variable should be?
Clash Royale CLAN TAG#URR8PPP
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.
BaseClass
SubClassA
SubClassB
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.
BaseClass
SubClassA
SubClassB
BaseClass
SubClassA
SubClassB
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?
SubClassA
SubClassB
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'
I think you should identify the problem first. What you’re trying to do is called co-variance & contra-variance. Changing a Type in subclass sometimes is possible, sometimes it’s not. If it’s exactly like your example, there are two options: 1. Either your design has flaws and you’re not following the Linkskov protocol, or 2. You should use generics
– farzadshbfn
Aug 11 at 5:06
3 Answers
3
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>
Ahh, this looks like what I was looking for! I often forget generics exist, have yet to put them into practice too much. Seems like as good a time to learn as any, other than a few years ago. I'll try it out and mark this as correct when it works.
– Jake T.
Aug 10 at 20:46
@JakeT. I hope it can help. There are also other technics about subclassing. I would like to advertise my article : ).
– ukim
Aug 10 at 20:52
The one hiccup was that I separate my delegate methods into extensions, and @objc does not currently support extensions of generics (or subclasses of generics). The fix was just moving those delegate methods into the original definition.
class BaseClass<T>: NSObject, DelegateProtocol where T:ServiceViewController {
is the format, for anyone wondering.– Jake T.
Aug 10 at 21:10
class BaseClass<T>: NSObject, DelegateProtocol where T:ServiceViewController {
Instead of putting the myObject
related code into BaseClass
, you could put it into a protocol extension. Consider this:
myObject
BaseClass
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.
myObject
Hmmm, I like the look of this more, but it would require more rework than the accepted answer. If I was starting from scratch, I'd probably go this route, as it is, the generic was pretty quick to implement
– Jake T.
Aug 10 at 21:11
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.
BaseClass
BaseObject
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()
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
I really appreciate the multitude of different answer that solve this problem. Without knowing terminology, it was difficult to search for what I was trying to do. It's cool to see so many different possible methods to do this, and I've got some more guided research to be doing now than the blind google searching I was before. I wish I could select multiple right answers.
– Jake T.
Aug 10 at 21:21