Answers:
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
存储为的实例上调用when时,SoftwareEngineer
它将调用该方法的重写版本。当logSalary
被调用的情况下,已强制转换为后Employee
,它会调用原始的实现(它不没有动态分派到重写版本,即使该实例实际上是一个Software Engineer
。
有关更多信息,请查看有关该功能的精彩WWDC视频:在Swift中使用值类型构建更好的应用程序
protocol Animal { var property : Int { get set } }
。如果您不希望该物业有
func logSalary()
到Employee协议声明中,则该示例将打印出overridden
对的两次调用logSalary()
。这是Swift 3.1中的版本。因此,您可以获得多态的好处。在两种情况下都将调用正确的方法。
请注意,此答案针对的是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)
所以基本上你得到:
Drivable
实现speed
Drivable
(accelerate
)的Drivable
保证不会被实例化,因为它只是一个协议该模型的行为实际上更像是特征,这意味着您可以遵循多种协议并采用其中的任何默认实现,而对于抽象超类,则只能限于简单的类层次结构。
UICollectionViewDatasource
。我想删除所有样板并将其封装在单独的协议/扩展中,然后由多个类重复使用。实际上,模板模式在这里会是完美的,但是……
我认为这是最接近Java abstract
或C#的语言abstract
:
class AbstractClass {
private init() {
}
}
请注意,为了 private
修饰符起作用,必须在单独的Swift文件中定义此类。
编辑:仍然,此代码不允许声明抽象方法,因此强制其实现。
最简单的方法是使用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()
(MyConcreteClass() as MyInterface).myMethod()
但是可以!密钥包含myMethod
在协议声明中;否则,通话会崩溃。
经过数周的努力,我终于意识到如何将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等。这有用吗?
有一种使用协议模拟抽象类的方法。这是一个例子:
protocol MyProtocol {
func doIt()
}
class BaseClass {
weak var myDelegate: MyProtocol?
init() {
...
}
func myFunc() {
...
self.myDelegate?.doIt()
...
}
}
class ChildClass: BaseClass, MyProtocol {
override init(){
super.init()
self.myDelegate = self
}
func doIt() {
// Custom implementation
}
}
实现抽象类的另一种方法是阻止初始化程序。我这样做是这样的:
class Element:CALayer { // IT'S ABSTRACT CLASS
override init(){
super.init()
if self.dynamicType === Element.self {
fatalError("Element is abstract class, do not try to create instance of this class")
}
}
}
我试图创建一个Weather
抽象类,但是使用协议并不理想,因为我不得不init
一遍又一遍地编写相同的方法。扩展协议并编写init
方法存在问题,尤其是因为我正在使用NSObject
遵循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
:
fileprivate init(param: Any...) {
// Initialize
}
将对基类的抽象属性和方法的所有引用移至协议扩展实现,将自约束移至基类。您将可以访问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;
}
}
在没有动态调度的限制下,您可以执行以下操作:
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()