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

如何基于API级别从Swift中的两个不同类派生一个类?,swift,inheritance,swift3,Swift,Inheritance,Swift3,我想使用一个带有类SwipeTableViewCell(派生自UITableViewCell)的库,但它只支持iOS 9,因此如果可能,我想派生自该类,但如果应用程序运行在9.0以下,则派生自普通UITableViewCell类 这是我能想到的最好的(不工作): 然后我尝试从该类中派生: class SomeOtherTableViewCell : MyTableViewCell { } Xcode为我提供了以下错误以及指向上述两个类定义的链接: SomeOtherTableViewCell.

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

这是我能想到的最好的(不工作):

然后我尝试从该类中派生:

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提到了实现目标应该采用的方法和一般模式

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

在您的情况下,您有SDK9,并且正在尝试支持iOS 8或更少的运行时。
SwipeTableViewCell
很可能在iOS 8中无法工作,因为它使用的API仅在iOS 9中可用。所有这些都不会阻止iOS 8设备上存在SwipeTableViewCell,它只是阻止它工作

你真的应该评估一下。如果将目标的部署目标更改为iOS 9并将其发布到应用商店,则运行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这很糟糕,所以你是说它根本不可能?也许我忽略了什么,但我假设你必须定义两个子类MyTableViewCell和MySwipeTableViewCell,然后使用
if#available()
在运行时创建一个或另一个的实例。是的,作为最后的手段,但我们希望将其用作许多不同TableViewCell的基类,因此它会复制大量代码。@MartinR和您提供了大量关于发生了什么的信息,特别是关于
的部分并没有阻止SwipeTableViewCell出现在iOS 8上
现在让我很感兴趣!我们将不得不调整需要多少注释才能使其运行,但这似乎是一条路要走。。活跃的iOS 8用户(对社区有贡献的用户)与花式滑动菜单的比例目前为1:0,因此值得稍微伤脑筋。:-)值得一提的是,在objective-c:-)中,您试图做的事情实际上非常简单
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
    }
}