Emitting a warning for a deprecated Swift protocol

2019-07-06 19:01发布

Suppose I have a protocol with a bar() method that has a default implementation — essentially the Swift way of making a protocol requirement optional for implementing types:

protocol Foo {
    func bar()
}

extension Foo {
    func bar() {
        print("default bar() implementaion")
    }
}

Now suppose that I decide to rename that method barrrr(), because more rs are better:

protocol Foo {
    func barrrr()
}

extension Foo {
    func barrrr() {
        print("default barrrr() implementaion")
    }
}

Existing code may still implement the method with the old name:

class Thinger: Foo {
    func bar() {
        print("custom bar() implementaion")
    }
}

This code thinks it’s customizing a Foo method, but it isn’t. Callers will look for barrrr(), and get the default implementation. Nobody calls bar().

I would therefore like to generate a warning for types that implement Foo and have a bar() method. This does not work:

protocol Foo {
    func barrrr()

    @available(*, deprecated: 0.99, renamed: "barrrr()")
    func bar()
}

extension Foo {
    func barrrr() {
        print("default barrrr() implementaion")
    }

    func bar() {
        fatalError("renamed barrrr()")
    }
}

class Thinger: Foo {
    func bar() {   // No warning here!
        print("custom bar() implementaion")
    }
}

Making the extension method final has no effect. Is there a way to do it? It needn’t be a friendly warning; any compiler error would suffice.

标签: swift swift3
2条回答
虎瘦雄心在
2楼-- · 2019-07-06 19:08

Without taking a position on whether it is a good thing, as suggested by another answer, exactly what you are asking for is not possible at least in Swift 3.

However, as I pointed out in response to a related question, it is possible to deprecate an entire protocol, and doing so would at least give you deprecation warnings at the implementing type level, if not precisely at the wanted property / method level.

查看更多
萌系小妹纸
3楼-- · 2019-07-06 19:16

If I understand the question correctly, I don't believe there is a way to do this--nor should there be.

You have a protocol, let's call it MyProtocol...

protocol MyProtocol {
    func myOldFunction()
}

extension MyProtocol {
    func myOldFunction() {
        print("doing my old things")
    }
}

And in a later release, you would like to rename a function within your protocol.

protocol MyProtocol {
    func myOldFunction() // now deprecated
    func myNewFunction()
}

The primary problem with throwing a deprecation warning on any class which conforms to MyProtocol and implemented myOldFunction() is that there's nothing wrong with classes implementing functions and properties that are not part of your protocol.

These methods or properties might still be perfectly valid implementations used by other things that don't care about your protocol.

Consider that nothing would stop us from doing this:

protocol ViewControllerDeprecations {
    func viewDidLoad() // mark deprecated
    func viewWillAppear(Bool) // mark deprecated
    // etc., for all the life cycle methods
}

extension UIViewController: ViewControllerDeprecations {}

Now every UIViewController subclass everywhere in any app that contains the file with the above code has these silly deprecation warnings all over it just because your particular protocol no longer uses these methods.

查看更多
登录 后发表回答