Jean Lebrument
Jean Lebrument

Reputation: 5169

Override optional attribute from superclass with a different type in Swift

I looking for a way which permits to override an optional attribute from a superclass with a different type.

If I test something like this:

protocol protocol1
{
    func testOne()
}

protocol protocol2 : protocol1
{
    func testTwo()
}

class class1
{
    var toto : protocol1?

    init()
    {

    }
}

class class2 : class1
{
    override var toto : protocol2?
}

let test = class2()

I've got an error in this line: override var toto : protocol2?

Property 'toto' with type 'protocol2' cannot override a property with type 'protocol1'

I've already google it and I found this post but it's for non-optional attribute only.

Upvotes: 4

Views: 1302

Answers (1)

Antonio
Antonio

Reputation: 72760

The answer in the question you linked doesn't do what you think. It doesn't change the type of a property defined in a protocol or superclass, it just adds a new property.

Swift (and I think any object oriented language) doesn't allow to redefine the type of a property, even if the new type is a subclass/subprotocol of the original type. I've explained that in the comments section of my answer to another similar question.

What you can do? Add a new computed property in class which attempts to downcast protocol1 to protocol2, and return nil if not possible:

class class2 : class1
{
    var toto2: protocol2? {
        if let toto2 = self.toto as? protocol2 {
            return toto2
        } else {
            return nil
        }
    }
}

Note that in order for the downcast to work you have to define both protocols as objc compatible

@objc protocol protocol1
{
    func testOne()
}

@objc protocol protocol2 : protocol1
{
    func testTwo()
}

Below the code I used for testing in playground:

@objc protocol protocol1
{
    func testOne()
}

@objc protocol protocol2 : protocol1
{
    func testTwo()
}

class classFromProtocol1 : protocol1 {
    func testOne() {
    }
}

class classFromProtocol2: protocol2 {
    func testOne() {
    }

    func testTwo() {
    }
}

class class1
{
    var toto : protocol1?

    init()
    {

    }
}

class class2 : class1
{
    var toto2: protocol2? {
        if let toto2 = self.toto as? protocol2 {
            return toto2
        } else {
            return nil
        }
    }
}

let test = class2()
test.toto = classFromProtocol1()
test.toto // prints {classFromProtocol1}
test.toto2 // prints nil, because toto contains an instance of classFromProtocol1

test.toto = classFromProtocol2()
test.toto // prints {classFromProtocol2}
test.toto2 // prints {classFromProtocol2}

Upvotes: 2

Related Questions