我想用快速语言创建一个抽象函数。可能吗?
class BaseClass {
func abstractFunction() {
// How do I force this function to be overridden?
}
}
class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}
我想用快速语言创建一个抽象函数。可能吗?
class BaseClass {
func abstractFunction() {
// How do I force this function to be overridden?
}
}
class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}
Answers:
Swift中没有抽象的概念(例如Objective-C),但是您可以这样做:
class BaseClass {
func abstractFunction() {
preconditionFailure("This method must be overridden")
}
}
class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}
assert(false, "This method must be overriden by the subclass")
。
fatalError("This method must be overridden")
preconditionFailure("Bla bla bla")
Swift中也有将在发行版本中执行的项目,并且也不需要return语句。编辑:刚刚发现,此方法基本上是相等的,fatalError()
但它是更合适的方法(更好的文档,在Swift中与一起引入precondition()
,assert()
并且在此处assertionFailure()
阅读)
您想要的不是基类,而是协议。
protocol MyProtocol {
func abstractFunction()
}
class MyClass : MyProtocol {
func abstractFunction() {
}
}
如果您在类中不提供abstractFunction,那就是错误。
如果您仍然需要其他行为的基类,则可以执行以下操作:
class MyClass : BaseClass, MyProtocol {
func abstractFunction() {
}
}
我从支持抽象基类的平台上将大量代码移植到Swift并大量运行。如果您真正想要的是抽象基类的功能,则意味着该类既可作为基于共享的类功能的实现(否则它将只是一个接口/协议),并且它定义了必须由以下类实现的方法派生类。
要在Swift中做到这一点,您将需要一个协议和一个基类。
protocol Thing
{
func sharedFunction()
func abstractFunction()
}
class BaseThing
{
func sharedFunction()
{
println("All classes share this implementation")
}
}
请注意,基类实现了共享方法,但没有实现协议(因为它没有实现所有方法)。
然后在派生类中:
class DerivedThing : BaseThing, Thing
{
func abstractFunction()
{
println("Derived classes implement this");
}
}
派生类从基类继承了sharedFunction,从而帮助它满足了协议的那一部分,并且协议仍然需要派生类来实现abstractFunction。
此方法的唯一真正缺点是,由于基类未实现协议,因此,如果您有一个需要访问协议属性/方法的基类方法,则必须在派生类中重写该方法,然后从那里进行调用基类(通过super)传递,self
以便基类具有协议实例来执行其工作。
例如,假设sharedFunction需要调用abstractFunction。协议将保持不变,并且类现在看起来像:
class BaseThing
{
func sharedFunction(thing: Thing)
{
println("All classes share this implementation")
thing.abstractFunction()
}
}
class DerivedThing : BaseThing, Thing
{
func sharedFunction()
{
super.sharedFunction(self)
}
func abstractFunction()
{
println("Derived classes implement this");
}
}
现在,派生类的sharedFunction满足了协议的那部分要求,但是派生类仍然能够以合理直接的方式共享基类逻辑。
这似乎是Apple处理UIKit中抽象方法的“官方”方式。看看UITableViewController
它的工作方式UITableViewDelegate
。您要做的第一件事就是添加一行:delegate = self
。好吧,这就是窍门。
protocol AbstractMethodsForClassX {
func abstractMethod() -> String
}
2.编写您的基类
/// It takes an implementation of the protocol as property (same like the delegate in UITableViewController does)
/// And does not implement the protocol as it does not implement the abstract methods. It has the abstract methods available in the `delegate`
class BaseClassX {
var delegate: AbstractMethodsForClassX!
func doSomethingWithAbstractMethod() -> String {
return delegate.abstractMethod() + " - And I believe it"
}
}
3.编写子类。
/// First and only additional thing you have to do, you must set the "delegate" property
class ClassX: BaseClassX, AbstractMethodsForClassX {
override init() {
super.init()
delegate = self
}
func abstractMethod() -> String {return "Yes, this works!"}
}
这是如何使用所有这些
let x = ClassX()
x.doSomethingWithAbstractMethod()
请与Playground一起查看输出。
UITableViewController
实现,UITableViewDelegate
但仍然需要通过显式设置delegate
属性将其注册为委托。getComments
对父委托有一个方法。注释类型很少,我想要与每个对象相关的类型。因此,delegate.getComments()
如果不重写该方法,我希望子类在编译时不进行编译。VC仅知道它有一个ParentDelegate
名为的对象delegate
,或BaseClassX
在您的示例中,但BaseClassX
没有抽象方法。我需要VC特别知道它正在使用SubclassedDelegate
。
一种实现方法是使用基类中定义的可选闭包,子代可以选择是否实现。
class BaseClass {
var abstractClosure?:(()->())?
func someFunc()
{
if let abstractClosure=abstractClosure
{
abstractClosure()
}
}
}
class SubClass : BaseClass {
init()
{
super.init()
abstractClosure={ ..... }
}
}
好吧,我知道我迟到了比赛,并且我可能会利用已经发生的变化。对于那个很抱歉。
无论如何,我想贡献我的答案,因为我喜欢进行测试fatalError()
,而aFAIK 的解决方案是不可测试的,有例外的解决方案则很难进行测试。
我建议使用更快捷的方法。您的目标是定义一个具有一些公共细节但尚未完全定义的抽象,即抽象方法。使用协议定义抽象中所有预期的方法,既定义的方法,也定义未的方法。然后创建一个协议扩展,以实现您所定义的方法。最后,任何派生类都必须实现协议,这意味着所有方法,但是作为协议扩展一部分的方法已经实现了。
用一个具体功能扩展您的示例:
protocol BaseAbstraction {
func abstractFunction() {
// How do I force this function to be overridden?
}
}
extension BaseAbstraction {
func definedFunction() {
print("Hello")
}
class SubClass : BaseAbstraction {
func abstractFunction() {
// No need to "Override". Just implement.
}
}
请注意,通过这样做,编译器再次成为您的朋友。如果该方法未“覆盖”,则您将在编译时收到错误,而不是fatalError()
在运行时会遇到的错误或异常。
使用assert
关键字强制抽象方法:
class Abstract
{
func doWork()
{
assert(false, "This method must be overriden by the subclass")
}
}
class Concrete : Abstract
{
override func doWork()
{
println("Did some work!")
}
}
let abstract = Abstract()
let concrete = Concrete()
abstract.doWork() // fails
concrete.doWork() // OK
但是,正如史蒂夫·瓦迪乔(Steve Waddicor)所提到的,您可能想要一个protocol
代替。
我了解这个问题,正在寻找相同的解决方案。协议与抽象方法不同。
在协议中,您需要指定您的类符合该协议,抽象方法意味着您必须重写该方法。
换句话说,协议是可选的,您需要指定基类和协议,如果不指定协议,则不必重写此类方法。
抽象方法意味着您想要一个基类,但需要实现自己的一两个方法,这是不一样的。
我需要相同的行为,这就是为什么我一直在寻找解决方案。我想Swift缺少这样的功能。
这个问题还有另一种选择,尽管与@jaumard的建议相比仍然有一个缺点。它需要一个return语句。尽管我错过了要求它的意义,因为它在于直接抛出异常:
class AbstractMethodException : NSException {
init() {
super.init(
name: "Called an abstract method",
reason: "All abstract methods must be overriden by subclasses",
userInfo: nil
);
}
}
然后:
class BaseClass {
func abstractFunction() {
AbstractMethodException.raise();
}
}
之后发生的一切都是无法实现的,所以我不明白为什么要强迫返回。
AbstractMethodException().raise()
吗
我不知道它是否会有用,但是在尝试构建SpritKit游戏时,我在抽象方法上遇到了类似的问题。我想要的是一个抽象的Animal类,该类具有诸如move(),run()等方法,但子类名称(和其他功能)应由子类提供。所以我最终做了这样的事情(经过Swift 2的测试):
import SpriteKit
// --- Functions that must be implemented by child of Animal
public protocol InheritedAnimal
{
func walkSpriteNames() -> [String]
func runSpriteNames() -> [String]
}
// --- Abstract animal
public class Animal: SKNode
{
private let inheritedAnimal: InheritedAnimal
public init(inheritedAnimal: InheritedAnimal)
{
self.inheritedAnimal = inheritedAnimal
super.init()
}
public required init?(coder aDecoder: NSCoder)
{
fatalError("NSCoding not supported")
}
public func walk()
{
let sprites = inheritedAnimal.walkSpriteNames()
// create animation with walking sprites...
}
public func run()
{
let sprites = inheritedAnimal.runSpriteNames()
// create animation with running sprites
}
}
// --- Sheep
public class SheepAnimal: Animal
{
public required init?(coder aDecoder: NSCoder)
{
fatalError("NSCoding not supported")
}
public required init()
{
super.init(inheritedAnimal: InheritedAnimalImpl())
}
private class InheritedAnimalImpl: InheritedAnimal
{
init() {}
func walkSpriteNames() -> [String]
{
return ["sheep_step_01", "sheep_step_02", "sheep_step_03", "sheep_step_04"]
}
func runSpriteNames() -> [String]
{
return ["sheep_run_01", "sheep_run_02"]
}
}
}