Search code examples
swiftswift3swift-extensions

Access static property of protocol extension


I'm trying to build a protocol exposing a static property, then use that static property in an extension of that protocol, but it seems to work only if I define this static property in the protocol extension as well. Basically the code I'm trying to get to work:

protocol NibInstantiable: class {
    static var bundle: Bundle? { get }
    static var nibName: String { get }
}

extension NibInstantiable where Self: UIViewController {
//    static var nibName: String {
//        return ""
//    }

    static func instantiate() -> Self {
        return Self(nibName: Self.nibName, bundle: Self.bundle ?? Bundle.main)
    }
}

This used to work basically as-is in Swift 2, but it's no longer the case in Swift 3. I can get it to work by uncommenting the nibName property in the protocol extension, but that would suppress compiler warnings if I forget to define this property in classes that implement this protocol.

Any idea what I'm missing ? Thanks !

EDIT: For reference, here is a Swift 2.3 version of that code that compiles and works without any issue:

protocol Instantiable {
    static var bundle: NSBundle? { get }
    static func instantiate() -> Self
}
extension Instantiable {
    static var bundle: NSBundle? {
        return NSBundle.mainBundle()
    }
}
// MARK: With Nib
protocol NibInstantiable: Instantiable {
    static var nibName: String { get }
}

extension NibInstantiable where Self: UIViewController {
    static func instantiate() -> Self {
        return Self(nibName: Self.nibName, bundle: Self.bundle ?? NSBundle.mainBundle())
    }
}

Solution

  • This looks like a bug to me (see the related bug report SR-2992) – the compiler thinks that there's a conflict between UIViewController's nibName instance property and your NibInstantiable protocol's nibName static property requirement. A simpler reproducible example would be:

    protocol Foo {
        static var bar : String { get }
    }
    
    class Bar {
        var bar = "" // commenting out this line allows the code to compile
    }
    
    extension Foo where Self : Bar {
        static func qux() {
            print(bar) // compiler error: Instance member 'bar' cannot be used on type 'Self'
        }
    }
    

    A simple workaround would be to just rename your protocol's nibName static property requirement.