【问题标题】:Deprecating protocols for Swift 3 upgrade弃用 Swift 3 升级协议
【发布时间】:2016-10-13 18:36:44
【问题描述】:

我有一个要升级到 Swift 3 的 iOS 框架。我希望 API 的方法签名遵循 Swift 3 约定,即为方法使用第一个命名参数,同时保持向后兼容性。很容易添加新的 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?

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

【问题讨论】:

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


    【解决方案1】:

    据我所知,在 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() {
        }
    }
    

    【讨论】:

    • 谢谢,使用基本协议的想法很有帮助。这样我只需要一个 delegate manager 类的属性。我只是希望我不必创建一个名称有趣的新协议——我的 Swift 2 协议有我想要使用的名称。 :(
    • 如果您自己的代码是该协议的唯一实现,例如在同一目标/项目/工作区中(即在易于搜索和替换的设置中),您始终可以将其重命名为“......遗产”之类的。但是,是的,我不能说我对这种解决方法感到兴奋,除了它将弃用的东西整齐地隔离到一个单元中(协议中只包含弃用的东西)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 2016-12-24
    • 2017-03-10
    • 1970-01-01
    相关资源
    最近更新 更多