Swift 3 升级的弃用协议

Deprecating protocols for Swift 3 upgrade

我有一个 iOS 框架,我正在升级到 Swift 3. 我希望 API 的方法签名遵循 Swift 在保持向后兼容性的同时为方法使用第一个命名参数的 3 个约定。 添加新的 API 方法签名并弃用旧方法签名非常容易。但是,使用委托中使用的协议处理此问题的最佳方法是什么?

API 对于 Swift 2.x:

 @objc(FooManager)
 public class FooManager {
   public var delegate: FooManagerDelegate?
   public func saveFoo(foo: Foo) {
     ...    
     delegate?.didSaveFoo(foo)
   } 
 ...
 }

 @objc public protocol FooManagerDelegate {
   @objc optional func didSaveFoo(foo: Foo)
 }

新 API Swift 3.x:

 @objc(FooManager)
 public class FooManager {
   public var delegate: FooManagerDelegate?

   @available(*, deprecated, message: "use didSave(foo: foo)")
   public func saveFoo(foo: Foo) {
     ...    
     delegate?.didSaveFoo(foo)
   }   
   public func save(foo: Foo) {
     ...    
     delegate?.didSave(foo: foo)
   } 
 ...
 }

 @objc public protocol FooManagerDelegate {
   @objc optional func didSaveFoo(foo: Foo)
   @objc optional func didSave(foo: Foo)
 }

上述解决方案可行,但它不会向继续使用旧委托方法的用户发出任何弃用警告。我可以创建一个新委托并弃用旧委托 class,但最终我不得不使用非标准委托 class 和 属性 命名。我不想让我的 FooManager 看起来像这样丑陋:

 public class FooManager {
   @available(*, deprecated, message: "use swift3delegate")
   public var delegate: FooDelegate?
   public var swift3delegate: Swift3FooDelegate?

是否有任何更好的解决方案可以在保持向后兼容性的同时将用户迁移到新的协议方法签名?

据我所知,Swift(也不 Objective-C?)不可能完全满足您的要求。引用 response to a related question:

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.

也就是说,协议的方法被弃用并不一定意味着方法蓝图是普遍要避免的,它可能只是意味着为了符合该协议的目的,方法或 属性 有问题的现在已弃用。

我完全明白这一点,我也想要这个功能,但据我所知 Swift 3 至少不提供它(据我所知 Objective-C 也不提供)。

一个解决方案是弃用整个协议,并生成一个您需要在 Swift 3 代码中声明符合性的新协议。所以,这有效:

@available(*, deprecated, message="use ModernX instead")
protocol X {}

class A: X {}

… 并且在您的 ModernX 协议中只包含除弃用方法之外的所有方法。使用不带已弃用方法的基本协议可以使它稍微不那么笨拙,但它确实是一个相当繁重的样板解决方法:

protocol BaseX {
    func foo()
    func bar()
}

@available(*, deprecated, message: "Use ModernX instead")
protocol X: BaseX {
    func theDeprecatedFunction()
}

protocol ModernX: BaseX {
    func theModernFunction()
}

// you'll get a deprecation warning here.
class A: X {
    func foo() {}
    func bar() {}

    func theDeprecatedFunction() {
    }
}