1

I have a protocol and a class which I want to extend. The protocol requires field of some type and the class has a field with the same name and the type as Implicitly Unwrapped Optional of this type.

Can this class be extended by this protocol? If yes, then how?

If I try to write an extension, Xcode give an error of not conforming. But if I add the field into the extension, it gives an error of redeclaration.

protocol Named {
   var name: String { get }
}

class Person {
   var name: String!
}


extension Person: Named { 
// Type 'Finances.Account' does not conform to protocol 'Named'
}

1 Answers1

4

Property names and types declared in a protocol must exactly be matched by the conforming classes.

So you cannot resolve the error without changing the property type in either the protocol or the conforming type. You could also rename one of the properties and add the matching property to the conforming type as a new field.

So either do:

protocol Named {
   var name: String { get }
}

class Person {
    var name: String

    init(_ name:String) {
        self.name = name
    }
}


extension Person: Named {

}

Or

protocol Named {
   var name: String { get }
}

class Person {
   var _name: String!
}


extension Person: Named { 
    var name: String {
        return _name
    }
}

As @user28434 pointed out, there's a(n ugly) workaround. You can create a wrapper protocol that matches the optionality of the Person class, make that protocol inherit from the original protocol, declare the non-optional variable in an extension on the new protocol and make Person conform to the new protocol instead of the original Named.

protocol Named {
    var name: String { get }
}

class Person {
    var name: String!
}

protocol Namedd: Named {
    var name: String! { get }
}

extension Namedd {
    var name: String {
        return name!
    }
}

extension Person: Namedd {

}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • `protocol` declaration is invalid (in the question too): access specifiers required `{get}`/`{get set}` – user28434'mstep Apr 11 '19 at 12:58
  • thanks for the reply. I understand both of your approaches, but what if restricted to change both of them? what can you suggest? – Artemis Shlesberg Apr 11 '19 at 12:59
  • 1
    @user28434 you're right, I updated the code to be compile-able and not just showcase the right approach – Dávid Pásztor Apr 11 '19 at 13:00
  • 1
    @ArtemiyShlesberg you mean you don't have access to the source code of either of those types? In that case sadly you cannot make given type conform to given protocol. – Dávid Pásztor Apr 11 '19 at 13:01
  • @DávidPásztor, well, there's one way, hacky and may not work in the future: you may declare new protocol, that inherits `Named` and in that protocol declare `var name: String! { get }` and in extension of that new protocol make non-optional `name` to return value of IUO `name` using `as` cast. And then extend `Person` with that new protocol. For some reason it is legal to have two `name` variables that way. – user28434'mstep Apr 11 '19 at 13:08
  • 1
    @user28434 you don't even need any casting, you can simply return the force unwrapped `name` variable in the new protocol. Check my updated answer – Dávid Pásztor Apr 11 '19 at 13:17