根据iOS版本使用类别的类实现



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

(注意:最初我使用if #available(iOS 11, *),但我必须在很多地方使用它,以至于我认为如果可能的话,拥有2个版本的两种版本。也许有一种方法可以以某种方式使用@Availble我专注于使用@Available而不是预编译器#IFDEF东西,因为它似乎是"可用"标签是现在在Swift中使用的首选方法吗?)

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)来获得实例,并因此而忘记了代码其余部分中的检查,并在可能的情况下使用新功能。

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

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

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

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

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

"类的两个版本"听起来像是基类和两个子类。您可以通过询问例如ProcessInfo。

我遇到了同样的问题。我最终通过在我只想在特定版本的iOS:

中添加@Available的方法来解决此问题:
@available(iOS 11.3, *)
func myMethod() { .. }

最新更新