Swift语言中的抽象类

时间:2014-06-08 20:16:04

标签: inheritance abstract-class subclass swift

有没有办法在Swift语言中创建一个抽象类,或者这是一个像Objective-C一样的限制?我想创建一个与Java定义为抽象类的抽象类。

10 个答案:

答案 0 :(得分:160)

Swift中没有抽象类(就像Objective-C一样)。最好的办法是使用Protocol,就像Java接口一样。

使用Swift 2.0,您可以使用协议扩展添加方法实现和计算属性实现。您唯一的限制是无法提供成员变量或常量没有动态调度

这种技术的一个例子是:

protocol Employee {
    var annualSalary: Int {get}
}

extension Employee {
    var biweeklySalary: Int {
        return self.annualSalary / 26
    }

    func logSalary() {
        print("$\(self.annualSalary) per year or $\(self.biweeklySalary) biweekly")
    }
}

struct SoftwareEngineer: Employee {
    var annualSalary: Int

    func logSalary() {
        print("overridden")
    }
}

let sarah = SoftwareEngineer(annualSalary: 100000)
sarah.logSalary() // prints: overridden
(sarah as Employee).logSalary() // prints: $100000 per year or $3846 biweekly

请注意,即使对于结构体,这也提供了类似于“抽象类”的功能,但类也可以实现相同的协议。

另请注意,实现Employee协议的每个类或结构都必须再次声明annualSalary属性。

最重要的是,请注意没有动态调度。在存储为logSalary的实例上调用SoftwareEngineer时,它会调用该方法的重写版本。在将实例转换为logSalary后在实例上调用Employee时,它会调用原始实现(即使实例实际上是{{},它也不会动态调度到重写版本1}}。

有关详情,请查看有关该功能的精彩WWDC视频:Building Better Apps with Value Types in Swift

答案 1 :(得分:47)

请注意,此答案针对的是Swift 2.0及以上

您可以使用协议和协议扩展来实现相同的行为。

首先,编写一个协议,作为所有必须在符合它的所有类型中实现的方法的接口。

protocol Drivable {
    var speed: Float { get set }
}

然后,您可以将默认行为添加到符合它的所有类型

extension Drivable {
    func accelerate(by: Float) {
        speed += by
    }
}

您现在可以通过实施Drivable来创建新类型。

struct Car: Drivable {
    var speed: Float = 0.0
    init() {}
}

let c = Car()
c.accelerate(10)

所以基本上你得到了:

  1. 编译时间检查,确保所有Drivable实施speed
  2. 您可以为符合Drivableaccelerate
  3. 的所有类型实施默认行为
  4. Drivable保证不会被实例化,因为它只是一个协议
  5. 这个模型实际上更像是traits,这意味着你可以符合多个协议并采用其中任何一个的默认实现,而对于一个抽象的超类,你只能局限于一个简单的类层次结构。

答案 2 :(得分:14)

我认为这是最接近Java的abstract或C#' abstract

class AbstractClass {

    private init() {

    }
}

请注意,为了使private修饰符起作用,您必须在单独的Swift文件中定义此类。

编辑:但是,此代码不允许声明抽象方法,从而强制执行。

答案 3 :(得分:9)

经过几周的努力,我终于意识到如何将Java / PHP抽象类翻译成Swift:

public class AbstractClass: NSObject {

    internal override init(){}

    public func getFoodToEat()->String
    {
        if(self._iAmHungry())
        {
            return self._myFavoriteFood();
        }else{
            return "";
        }
    }

    private func _myFavoriteFood()->String
    {
        return "Sandwich";
    }

    internal func _iAmHungry()->Bool
    {
        fatalError(__FUNCTION__ + "Must be overridden");
        return false;
    }
}

public class ConcreteClass: AbstractClass, IConcreteClass {

    private var _hungry: Bool = false;

    public override init() {
        super.init();
    }

    public func starve()->Void
    {
        self._hungry = true;
    }

    public override func _iAmHungry()->Bool
    {
        return self._hungry;
    }
}

public protocol IConcreteClass
{
    func _iAmHungry()->Bool;
}

class ConcreteClassTest: XCTestCase {

    func testExample() {

        var concreteClass: ConcreteClass = ConcreteClass();

        XCTAssertEqual("", concreteClass.getFoodToEat());

        concreteClass.starve();

        XCTAssertEqual("Sandwich", concreteClass.getFoodToEat());
    }
}

但是我认为Apple没有实现抽象类,因为它通常使用委托+协议模式。例如,上面相同的模式会更好地完成:

import UIKit

    public class GoldenSpoonChild
    {
        private var delegate: IStomach!;

        internal init(){}

        internal func setup(delegate: IStomach)
        {
            self.delegate = delegate;
        }

        public func getFoodToEat()->String
        {
            if(self.delegate.iAmHungry())
            {
                return self._myFavoriteFood();
            }else{
                return "";
            }
        }

        private func _myFavoriteFood()->String
        {
            return "Sandwich";
        }
    }

    public class Mother: GoldenSpoonChild, IStomach
    {

        private var _hungry: Bool = false;

        public override init()
        {
            super.init();
            super.setup(self);
        }

        public func makeFamilyHungry()->Void
        {
            self._hungry = true;
        }

        public func iAmHungry()->Bool
        {
            return self._hungry;
        }
    }

    protocol IStomach
    {
        func iAmHungry()->Bool;
    }

    class DelegateTest: XCTestCase {

        func testGetFood() {

            var concreteClass: Mother = Mother();

            XCTAssertEqual("", concreteClass.getFoodToEat());

            concreteClass.makeFamilyHungry();

            XCTAssertEqual("Sandwich", concreteClass.getFoodToEat());
        }
    }

我需要这种模式,因为我想在UITableViewController中使用一些方法,例如viewWillAppear等。这有用吗?

答案 4 :(得分:8)

最简单的方法是在协议扩展上对抽象方法(非变量)使用fatalError("Not Implemented")调用。

protocol MyInterface {
    func myMethod() -> String
}


extension MyInterface {

    func myMethod() -> String {
        fatalError("Not Implemented")
    }

}

class MyConcreteClass: MyInterface {

    func myMethod() -> String {
        return "The output"
    }

}

MyConcreteClass().myMethod()

答案 5 :(得分:6)

有一种方法可以使用Protocols模拟抽象类。 这是一个例子:

protocol MyProtocol {
   func doIt()
}

class BaseClass {
    var myDelegate: MyProtocol!

    init() {
        ...
    }

    func myFunc() {
        ...
        self.myDelegate.doIt()
        ...
    }
}

class ChildClass: BaseClass, MyProtocol {
    override init(){
        super.init()
        self.myDelegate = self
    }

    func doIt() {
        // Custom implementation
    }
}

答案 6 :(得分:1)

这是一个非常古老的问题,但仍然......这是在 Swift 5.2 上编译并按预期工作的实际代码片段:

protocol Context {
    init() throws
    func out(_ aStr: String) throws
    // Other stuff
}

class AbstractContext: Context {
    required init() throws {
        if Self.self === AbstractContext.self {
            preconditionFailure("Call to abstract method \(Self.self).\(#function)") 
        }
    }

    func out(_ aStr: String) throws {
        preconditionFailure("Call to abstract method \(Self.self).\(#function)") 
    }

    // Other stuff
}

class CompileContext: AbstractContext {
    required init() throws {}

    override func out(_ aStr: String) throws {
        print(aStr)
    }

    // Other stuff
}

这是我删除 CompileContext.out 后得到的:

Fatal error: Call to abstract method CompileContext.out(_:): file swiftpg/contexts.swift, line 28

答案 7 :(得分:0)

我试图制作一个Weather抽象类,但使用协议并不理想,因为我不得不一遍又一遍地编写相同的init方法。扩展协议并编写init方法会产生问题,尤其是因为我使用符合NSObject的{​​{1}}。

所以我想出了NSCoding一致性:

NSCoding

至于required init?(coder aDecoder: NSCoder) { guard type(of: self) != Weather.self else { fatalError("<Weather> This is an abstract class. Use a subclass of `Weather`.") } // Initialize... }

init

答案 8 :(得分:0)

将对Base类的抽象属性和方法的所有引用移动到协议扩展实现,其中Self约束为Base类。您将获得对Base类的所有方法和属性的访问权限。另外,编译器检查派生类的协议中抽象方法和属性的实现

protocol Commom:class{
  var tableView:UITableView {get};
  func update();
}

class Base{
   var total:Int = 0;
}

extension Common where Self:Base{
   func update(){
     total += 1;
     tableView.reloadData();
   }
} 

class Derived:Base,Common{
  var tableView:UITableView{
    return owner.tableView;
  }
}

答案 9 :(得分:0)

由于没有动态调度的限制,您可以执行以下操作:

import Foundation

protocol foo {

    static var instance: foo? { get }
    func prt()

}

extension foo {

    func prt() {
        if Thread.callStackSymbols.count > 30 {
            print("super")
        } else {
            Self.instance?.prt()
        }
    }

}

class foo1 : foo {

    static var instance : foo? = nil

    init() {
        foo1.instance = self
    }

    func prt() {
        print("foo1")
    }

}

class foo2 : foo {

    static var instance : foo? = nil

    init() {
        foo2.instance = self
    }

    func prt() {
        print("foo2")
    }

}

class foo3 : foo {

    static var instance : foo? = nil

    init() {
        foo3.instance = self
    }

}

var f1 : foo = foo1()
f1.prt()
var f2 : foo = foo2()
f2.prt()
var f3 : foo = foo3()
f3.prt()