2

This is my inheritance structure

Protocols

protocol BaseProtocol {
}

protocol ChildProtocol: BaseProtocol {
}

Classes

class BaseClass: NSObject {

    var myVar: BaseProtocol!
}

class ChildClass: BaseClass {

    override var myVar: ChildProtocol!
}

I'm receiving a compiler error:

Property 'myVar' with type 'ChildProtocol!' cannot override a property with type 'BaseProtocol!'

What is the best approach to achieve this?

UPDATE

I updated the question trying to implement the solution with generics but it does not work :( This is my code (now the real one, without examples)

Protocols

protocol TPLPileInteractorOutput {
}

protocol TPLAddInteractorOutput: TPLPileInteractorOutput {  

    func errorReceived(error: String)
}

Classes

class TPLPileInteractor<T: TPLPileInteractorOutput>: NSObject, TPLPileInteractorInput {

    var output: T!
}

And my children

class TPLAddInteractor<T: TPLAddInteractorOutput>: TPLPileInteractor<TPLPileInteractorOutput>, TPLAddInteractorInput {
}

Well, inside my TPLAddInteractor I can't access self.output, it throws a compiler error, for example

'TPLPileInteractorOutput' does not have a member named 'errorReceived'

Besides that, when I create the instance of TPLAddInteractor

let addInteractor: TPLAddInteractor<TPLAddInteractorOutput> = TPLAddInteractor()

I receive this other error

Generic parameter 'T' cannot be bound to non-@objc protocol type 'TPLAddInteractorOutput'

Any thoughts?

emenegro
  • 6,901
  • 10
  • 45
  • 68
  • [This Might be Helpful](http://stackoverflow.com/questions/24094158/overriding-superclass-property-with-different-type-in-swift) and [This](http://stackoverflow.com/questions/26188903/swift-override-class-variables) – Bista Mar 18 '15 at 12:16
  • Thank you @UmangBista but the accepted solution does not work for me, compiler says I cannot make a downcast from type to the other type. – emenegro Mar 18 '15 at 12:46

3 Answers3

2

@tskulbru is correct: it can't be done, and this has nothing to do with your protocols. Consider the example below, which also fails…this time with Cannot override with a stored property 'myVar':

class Foo {
}

class Goo: Foo {
}

class BaseClass: NSObject {
   var myVar: Foo!
}

class ChildClass: BaseClass {
   override var myVar: Foo!
}

To understand why, let's reexamine the docs:

Overriding Properties

You can override an inherited instance or class property to provide your own custom getter and setter for that property, or to add property observers to enable the overriding property to observe when the underlying property value changes.

The implication is that if you are going to override a property, you must write your own getter/setter, or else you must add property observers. Simply replacing one variable type with another is not allowed.

Now for some rampant speculation: why is this the case? Well, consider on the one hand that Swift is intended to be optimized for speed. Having to do runtime type checks in order to determine whether your var is in fact a Foo or a Bar slows things down. Then consider that the language designers likely have a preference for composition over inheritance. If both of these are true, it's not surprising that you cannot override a property's type.

All that said, if you needed to get an equivalent behavior, @tskulbru's solution looks quite elegant, assuming you can get it to compile. :)

clozach
  • 5,118
  • 5
  • 41
  • 54
  • Thanks clozach. I will take a look at the docs because I'm starting to learn Swift and I have not dived a lot on generics more than the basis. – emenegro Mar 18 '15 at 15:01
1

I don't think you can do that with protocols

The way i would solve the problem you are having is with the use of generics. This means that you essentially have the classes like this (Updated to a working example).

Protocols

protocol BaseProtocol {
    func didSomething()
}
protocol ChildProtocol: BaseProtocol {
    func didSomethingElse()
}

Classes

class BaseClass<T: BaseProtocol> {
    var myProtocol: T?

    func doCallBack() {
        myProtocol?.didSomething()
    }
}
class ChildClass<T: ChildProtocol> : BaseClass<T> {
    override func doCallBack() {
        super.doCallBack()
        myProtocol?.didSomethingElse()
    }
}

Implementation/Example use

class DoesSomethingClass : ChildProtocol {
    func doSomething() {
        var s = ChildClass<DoesSomethingClass>()
        s.myProtocol = self
        s.doCallBack()
    }

    func didSomething() {
        println("doSomething()")
    }
    func didSomethingElse() {
        println("doSomethingElse()")
    }
}

let foo = DoesSomethingClass()
foo.doSomething()

Remember, you need a class which actually implements the protocol, and its THAT class you actually define as the generic type to the BaseClass/ChildClass. Since the code expects the type to be a type which conforms to the protocol.

tskulbru
  • 2,336
  • 1
  • 20
  • 38
  • Thanks tskulbru but that is not exactly the same, my ChildClass and BaseClass does not conform to the protocol, that are the variables. – emenegro Mar 18 '15 at 14:35
  • using my answer doesnt make the class conform to the protocol, it makes the class contain a generic type T, which is of type BaseProtocol or derivatives – tskulbru Mar 19 '15 at 08:49
  • Thanks again I'm trying to implement it, I'll let you know – emenegro Mar 19 '15 at 09:37
  • Hi @tskulbru, I've updated the question, I cannot make this working :( – emenegro Mar 20 '15 at 07:49
  • @emenegro so, I've updated to a working example. See my updated code. You can paste the code into a playground to test it out. I can see in your updated code that you don't grasp some of the concepts of protocols and generics, hopefully my updated answer will help you. – tskulbru Mar 20 '15 at 11:23
0

There are two ways you can go with your code, depending what you want to achieve with your code (you didn't tell us).

The simple case: you just want to be able to assign an object that confirms to ChildProtocol to myVar. Solution: don't override myVar. Just use it in ChildClass. You can do this by design of the language Swift. It is one of the basics of object oriented languages.

Second case: you not only want to enable assigning instances of ChildProtocol, you also want to disable to be able to assign instances of BaseProtocol. If you want to do this, use the Generics solution, provided here in the answers section.

If you are unsure, the simple case is correct for you.

Gerd

Gerd Castan
  • 6,275
  • 3
  • 44
  • 89
  • Hi Gerd. I thought the case was clear, I want to override the var in the base with another var conforming to a protocol that conforms to the base's var protocol. If I use the base class I have one behavior, if I use the child, I have both behaviors, and I can use it polymorphically taking into account the base class. I think this is very common and pretty straightforward. I'm trying to achieve the generics solution. – emenegro Mar 19 '15 at 09:33