弃用Swift 3升级协议

时间:2016-10-13 18:36:44

标签: swift delegates swift3 backwards-compatibility swift-protocols

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

Swift 2.x的API:

 @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)
 }

Swift 3.x的新API:

 @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)
 }

上述解决方案可行,但不会向用户提供任何弃用警告,以便继续使用旧的委托方法。我可以创建一个新的委托并弃用旧的委托类,但最后我必须拥有非标准的委托类和属性命名。我讨厌让我的FooManager看起来像这样丑陋:

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

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

1 个答案:

答案 0 :(得分:2)

根据我的知识,究竟你要求的是Swift(也不是Objective-C?)。引用response to a related question

  

在符合MyProtocol并实现myOldFunction()的任何类上抛出弃用警告的主要问题是,实现不属于您的协议的函数和属性的类没有任何问题。

也就是说,不推荐使用协议的方法并不一定意味着方法蓝图是普遍要避免的,它只是意味着为了符合该协议,方法或有问题的财产现已弃用。

我完全明白了这一点,我也喜欢这个功能,但据我所知,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() {
    }
}