Search code examples
swiftswift-protocolsswift-extensions

How to resolve collision between protocol and class fields types?


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'
}

Solution

  • 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 {
    
    }