如何基于 API 级别从 Swift 中的两个不同类派生一个类?



我想使用带有类SwipeTableViewCell(派生自UITableViewCell(的库,但它只支持iOS 9,所以如果可能的话,我想从该类派生,但如果应用程序运行在9.0以下,则从普通的UITableViewCell类派生。

这是我能想到的最好的(不起作用(:

@available(iOS, obsoleted: 9.0)
class MyTableViewCell : UITableViewCell {
}
@available(iOS 9.0, *)
class MyTableViewCell : SwipeTableViewCell {
}

然后我尝试从该类派生:

class SomeOtherTableViewCell : MyTableViewCell {
}

Xcode 给了我以下错误和指向上述两个类定义的链接:

SomeOtherTableViewCell.swift:34:31: 'MyTableViewCell' is ambiguous for type lookup in this context
Found this candidate
Found this candidate

在 Swift 中,根据 API 级别有条件地从两个不同的类派生有什么很酷的方法?

不幸的是(或者幸运的是,这取决于你如何看待它(,从语言的角度来看,你试图做的事情在 Swift 或 Objective-C 上是不可能的。您使用的@available属性是告诉编译器,仅当您编译的部署目标大于指定目标的目标时,此类才可用。

@MartinR提到了实现目标应该采用的 #available 和一般模式。

这两件事之所以可用且是支持向后兼容性所必需的,是因为编译的代码不一定包含有关运行时的所有信息。编译器/链接器在编译时使用 SDK 的标头和模块映射检查是否存在 API、类等。但是,你的应用在运行时与系统框架动态链接。这种模式就是为什么你的应用不必随它使用的 SDK 的每个部分的副本一起分发的原因。

在您的情况下,您拥有 SDK9 并尝试支持 iOS 8 或更低版本的运行时。该SwipeTableViewCell在iOS 8中不起作用,可能是因为它使用了仅在iOS 9中可用的API。所有这些都不会阻止SwipeTableViewCell存在于iOS 8设备上,只是阻止它工作。

你真的应该评估你是否需要支持iOS 8。如果您将目标的部署目标更改为 iOS 9 并将其发布到 App Store,则运行 iOS 8 的用户将无法获得更新或安装它。

更新

经过一些思考和研究,我想出了适合您情况的可能解决方案。我只在依赖于 UI 故事板的环境中对其进行了测试,但我认为它可以优雅地桥接您的 iOS 目标。

import UIKit
class ViewController: UITableViewController {
@IBOutlet var staticCell: Any? // In the storyboard, tell the cell to by a "MySwipeableCell"
override func viewDidLoad() {
super.viewDidLoad()
if staticCell is SwipeTableViewCell {
print("This class was converted magically, which means we're on iOS 9 or later")
}
}
}
class SwipeTableViewCell: UITableViewCell {
// Standin for your library class
}
class MySwipeableCell: UITableViewCell {
override func awakeAfter(using aDecoder: NSCoder) -> Any? {
if #available(iOS 9, *) {
// This will replace the MySwipeableCell with an instance of SwipeTableViewCell instead
return SwipeTableViewCell.init(coder: aDecoder)
}
return self
}
}

相关内容

最新更新