4

iOS 11 最近添加了一个我想使用的新功能,但我仍然需要支持旧版本的 iOS。有没有办法两次编写同一个类,并让较新版本的 iOS 使用该类的一个版本,而旧版本的 iOS 使用另一个?

(注意:最初我使用if #available(iOS 11, *)但我不得不在很多地方使用它,我认为如果可能的话拥有 2 个版本的类会更干净。也许有一种使用@availble 的方法?我专注于使用@可用而不是预编译器#IFDEF 的东西,因为“可用”标签似乎是现在在 Swift 中执行此操作的首选方式?)

4

4 回答 4

7
protocol Wrapper {

}

extension Wrapper {
    static func instantiate(parametersAB: Any*) -> Wrapper{
        if #available(iOS 11.0, *) {
            return A(parametersA)
        } else {
            return B(parametersB)
        }
    }
}

@available(iOS 11.0,*)
class A: Wrapper {
    //Use new feature of iOS 11
    init(parametersA: Any*) {
      ...
    }
}

class B: Wrapper {
    //Fallback
    init(parametersB: Any*) {
      ...
    }
}

现在您通过调用获取您的实例Wrapper.instationate(params),这样您就可以忘记检查其余代码,并尽可能使用新功能。

仅当您可以为两个类建立相同的接口(即使它是该方法的虚拟版本)时,此解决方案才有可能。

于 2017-09-07T19:46:24.647 回答
2

高质量的代码遵循几个原则。一个是单一责任原则,它指出一个班级应该只有一个责任,或者 - 正如鲍勃叔叔所说 - 班级改变应该只有一个理由。
另一个原则是依赖倒置原则:一个类不应该依赖于较低级别的类,而应该依赖于这些较低级别的类实现的抽象(协议)。这也意味着必须将所有依赖项传递到使用它们的类中。

应用于您的问题的一种解决方案可能是:

  1. 视图控制器具有定义为协议的数据源属性。
  2. 有几个类实现了这个协议,每个类都用于不同的 iOS 版本。
  3. 存在一个只准备选择正确版本的课程。这个版本选择可以通过多种方式完成,我坚持#available

数据源协议:

protocol ViewControllerDataSourcing: class {
    var text:String { get }
}

它的实现:

class ViewControllerDataSourceIOS10: ViewControllerDataSourcing {
    var text: String {
        return "This is iOS 10"
    }
}

class ViewControllerDataSourceIOS11: ViewControllerDataSourcing {
    var text: String {
        return "This is iOS 11"
    }
}

class ViewControllerDataSourceIOSUnknown: ViewControllerDataSourcing {
    var text: String {
        return "This is iOS Unknown"
    }
}

选择正确版本类的类:

class DataSourceSelector{
    class func dataSource() -> ViewControllerDataSourcing {
        if #available(iOS 11, *) {
            return ViewControllerDataSourceIOS11()
        }
        if #available(iOS 10, *) {
            return ViewControllerDataSourceIOS10()
        }
        return ViewControllerDataSourceIOSUnknown()
    }
}

最后是视图控制器

class ViewController: UIViewController {

    var dataSource: ViewControllerDataSourcing?
    
    @IBOutlet weak var label: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = DataSourceSelector.dataSource()
        label.text = dataSource?.text
    }
}

这是一个非常简单的示例,应该突出显示负责的不同组件。

于 2017-09-07T20:36:56.733 回答
0

我遇到了同样的问题。我最终通过在我只想在特定版本的 iOS 中支持的方法上方添加 @available 来解决这个问题:

@available(iOS 11.3, *)
func myMethod() { .. }
于 2018-02-26T12:50:46.247 回答
0

“一个类的两个版本”听起来像是一个基类和两个子类。您可以在运行时通过询问例如 ProcessInfo 来根据系统版本实例化所需的子类。

于 2017-09-07T16:53:41.390 回答