如何根据 API 级别从 Swift 中的两个不同类派生一个类?
Posted
技术标签:
【中文标题】如何根据 API 级别从 Swift 中的两个不同类派生一个类?【英文标题】:How to derive one class from two different classes in Swift based on API level? 【发布时间】:2017-07-06 13:54:29 【问题描述】:我想使用一个带有 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 级别有条件地从两个不同的类派生的酷方法是什么?
【问题讨论】:
继承是在编译时评估的,而不是在运行时。 @MartinR 这很糟糕,所以你说这根本不可能? 也许我忽略了一些东西,但我假设您必须定义两个子类 MyTableViewCell 和 MySwipeTableViewCell,然后在运行时使用if #available()
创建其中一个或另一个的实例。
是的,作为最后的手段,但我们想将它用作许多不同 TableViewCells 的基类,所以它会重复很多代码。
【参考方案1】:
不幸的是(或者幸运的是,取决于你如何看待它),从语言的角度来看,你想要做的正是 Swift 或 Objective-C 无法实现的。您使用的@available
属性是告诉编译器,只有当您编译的目标具有大于您指定的deployment target 时,该类才可用。
@MartinR 提到了#available 以及您应该采用的实现目标的一般模式。
这两个东西之所以可用并且是支持向后兼容性所必需的,是因为编译后的代码不一定包含有关运行时的所有信息。编译器/链接器在编译时使用 SDK 的标头和模块映射来检查 API、类等是否存在。但是,您的应用程序在运行时与系统框架动态链接。这种模式就是为什么您的应用不必随其使用的 SDK 的每个部分的副本一起分发的原因。
在您的情况下,您拥有 SDK9 并尝试支持 iOS 8 或更低版本的运行时。 SwipeTableViewCell
在 iOS 8 中可能不起作用,因为它使用了仅在 iOS 9 中可用的 API。所有这些都不会阻止 SwipeTableViewCell
在 iOS 8 设备上存在,它只是阻止它工作。
你真的应该评估whether you need to support 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
【讨论】:
@MartinR 和您对正在发生的事情提供了很好的意见,尤其是关于doesn't prevent SwipeTableViewCell from existing on iOS 8
的部分现在让我很感兴趣!我们将不得不修改使其可运行所需的注释数量,但看起来是一种方法.. 活跃的 iOS 8 用户(为社区做出贡献)与 Fancy Swipe Menu 目前是 1:0,所以值得得到一点脑损伤。 :-)
值得一提的是,在 Objective-c 中,您尝试做的事情实际上非常简单 :-)以上是关于如何根据 API 级别从 Swift 中的两个不同类派生一个类?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 swift 3 中为 UITable 视图提供单元格缩进级别?
从 Google Maps API 中的单个 LatLong 确定缩放级别
如何根据 iOS 中的两个条件从 AppDelegate 呈现两个不同的 ViewController?
iOS Swift:如何根据特定属性查找不同类型数组的唯一成员