Abstract Class and Abstract Function in Swift

Abstract functions in Swift Language

There no concept of abstract in Swift (like Objective-C) but you can do this :

class BaseClass {
func abstractFunction() {
preconditionFailure("This method must be overridden")
}
}

class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}

abstract class and abstract function in swift

Swift unfortunately doesn't support abstract classes and methods.

To achieve a similar effect, in Swift we use protocols (Interfaces in Java).

So an example of your class would be:

protocol Fetcher {
var items: [Item] { get set }
func fetch()
func parse()
}

The one thing you can do, is mark members of a class final to prevent them from being overridden in their subclass.

If you want a default implementation of one of your functions, you extend your protocol:

extension Fetcher {
func fetch() {
//SOME CODE
parse()
//SOME CODE
}
}

In which you won't need to implement this in your target class.

So for example, using the above protocol:

class Foo: Fetcher {
var items = [Item]()

// No need for fetch method, since it's already implemented

func parse() {
// Do something
}
}

Note, that the above implementation doesn't contain the method fetch since it's already implemented in the protocol extension.

Abstract classes in Swift Language

There are no abstract classes in Swift (just like Objective-C). Your best bet is going to be to use a Protocol, which is like a Java Interface.

With Swift 2.0, you can then add method implementations and calculated property implementations using protocol extensions. Your only restrictions are that you can't provide member variables or constants and there is no dynamic dispatch.

An example of this technique would be:

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

Notice that this is providing "abstract class" like features even for structs, but classes can also implement the same protocol.

Also notice that every class or struct that implements the Employee protocol will have to declare the annualSalary property again.

Most importantly, notice that there is no dynamic dispatch. When logSalary is called on the instance that is stored as a SoftwareEngineer it calls the overridden version of the method. When logSalary is called on the instance after it has been cast to an Employee, it calls the original implementation (it doesn't not dynamically dispatch to the overridden version even though the instance is actually a Software Engineer.

For more information, check great WWDC video about that feature: Building Better Apps with Value Types in Swift

Abstract methods in Swift?

As of today (April 7, 2016), the proposal to introduce abstract classes and methods to Swift (SE-0026) has been deferred.

Joe Groff posted the following in swift-evolution-announce on March 7, 2016:

The proposal has been deferred from Swift 3. Discussion centered around whether abstract classes fit in the direction of Swift as a "protocol-oriented" language. Beyond any religious dogmas, Swift intends to be a pragmatic language that lets users get work done. The fact of the matter today is that one of Swift's primary target platforms is the inheritance-heavy Cocoa framework, and that Swift 2's protocols fall short of abstract classes in several respects [...].

We'd like to revisit this feature once the core goals of Swift 3 have been addressed, so we can more accurately consider its value in the context of a more complete generics implementation, and so we can address the finer points of its design.

I encourage you to read the full email, but I think the conclusion is the same as what you came up with in your question: we're currently stuck with the Objective-C way of doing things (raising exceptions).

Swift - mixing abstract and concrete methods

I would implement it like this:

class AbstractAnimal
{
// Fully abstract method
func methodThatReturnsSomething() -> String {
fatalError("methodThatReturnsSomething() is abstract and must be overriden!");
}

func eyeCount() -> Int {
return 2;
}
}

fatalError prevents Xcode from complaining that abstract method methodThatReturnsSomething() doesn't actually return anything.

Abstract classes in Swift

I strongly suggest you redesign your model in Swift. Just like when translating spoken languages, the outcome can sound very awkward, programming languages, when translated, can look awkward too. If you still want to translate from Java, read on.


The really hard problem to solve here is that B is generic. If B wasn't generic, everything would work way better in Swift.

For now, you just have to use a class and pretend it is a protocol:

class A {
func sayHello() {
print("Hello from A")
}
}

class B<R> : A {
func sayHi() {
print("Hi from B")
}
}

class C<M, R> : B<R> {
// this fatalError() thing is really ugly, but I can't think of any other workarounds
func get(r: R) -> [M] { fatalError() }
func sayGracias() {
print("Gracias from C")
}
}

class D : C<String, String> {
override func get(r: String) -> [String] {
return [r]
}
}

let d = D()
d.sayHello()
d.sayHi()
d.sayGracias()
print(d.get(r: "Hello"))

If B were not generic (you are not using the generic argument anyway), then this can be done:

class A {
func sayHello() {
print("Hello from A")
}
}

class B : A {
func sayHi() {
print("Hi from B")
}
}

protocol C {
// associated types in Swift are kind of like generic parameters for protocols
associatedtype M
associatedtype R
func get(r: R) -> [M]
}

extension C {
func sayGracias() {
print("Gracias from C")
}
}

// You have to specify that D inherits from B as well since protocols can't inherit from classes
class D : B, C {
typealias M = String
typealias R = String

func get(r: String) -> [String] {
return [r]
}
}

let d = D()
d.sayHello()
d.sayHi()
d.sayGracias()
print(d.get(r: "Hello"))


Related Topics



Leave a reply



Submit