Apple way in Swift instead of an override? - swift

what approach does Apple use in Swift instead of override, how can I write this without using the #objc marker
import Foundation
class A {
init() {}
}
extension A {
#objc func foo() {
print("foo")
}
}
class B: A {
override func foo() {
print("yes2")
}
}
A().foo()
B().foo()
maybe protocols? but how?

You can define a protocol and provide a default method implementation. Then all you need is to comform to that protocol and provide its own foo method if necessary:
protocol Fooable {
func foo()
}
extension Fooable {
func foo() {
print("default implementation")
}
}
class A: Fooable { }
class B: A {
func foo() {
print("B implementationn")
}
}
let a = A()
let b = B()
a.foo()
b.foo()
This will print
default implementation
B implementationn

Related

Protocol extension to be applied to several types

I have a protocol, for instance:
protocol P {
func foo()
}
It is possible to make default implementation for some type:
extension P where Self == Int {
func foo() {
// do something
}
}
But how to have same default implementation for several types? Like this:
extension P where Self == Int or Self == Float {
func foo() {
// do something
}
}
You can unite the types with another protocol (for example HasDefaultFoo). This allows the types to decide when adopting the protocol if they want the default implementation.
protocol P {
func foo()
}
protocol HasDefaultFoo {
func foo()
}
extension Int: P, HasDefaultFoo { }
extension Float: P, HasDefaultFoo { }
extension P where Self: HasDefaultFoo {
func foo() {
print(self)
}
}
extension Double: P {
func foo() {
print("I provide my own foo()")
}
}
Example:
5.foo()
(5.5 as Float).foo()
5.5.foo()
Output:
5
5.5
I provide my own foo()

Swift Inheritance: Super's Super

Supposing to have this three classes with this simply hierarchy:
class A {
func foo() {
print("A")
}
}
class B: A {
override func foo() {
super.foo()
print("B")
}
}
class C: B {
override func foo() {
// *******
print("C")
}
}
In class C, in overrided method foo I want to call a method foo: is it possible?
In C++ this can be achieved with C->A::foo(), but how do I do this in Swift?
super.foo() should be sufficient, since B prints "B" and calls super to print "A".
class C: B {
override func foo() {
super.foo()
print("C")
}
}
let c = C()
c.foo()
Output:
A
B
C
If you want to intentionally expose A's foo() from B, you need to create a new accessor:
class B: A {
override func foo() {
super.foo()
print("B")
}
func exposeFoo() {
super.foo()
}
}
class C: B {
override func foo() {
super.exposeFoo()
print("C")
}
}
Or, use NSObject and the power of the Objective-C runtime:
class A: NSObject { // make sure your base class inherits from NSObject
func foo() {
print("A")
}
}
// ...
class C: B {
override func foo() {
guard let superSuper = self.superclass?.superclass() else {
return; // no super super
}
let fooImp = class_getMethodImplementation(superSuper, "foo")
typealias MyCFunction = #convention(c) (AnyObject, Selector) -> Void
let curriedImplementation = unsafeBitCast(fooImp, MyCFunction.self)
curriedImplementation(self, selector) // prints A
}
}

How can I add the same methods to different classes?

Is it possible to add the same methods to different classes?
Example:
class FilterableTable: UITableViewController { ... }
class FilterableCollection: UICollectionViewController { ... }
extension FilterableTable, FilterableCollection { // I know this line is wrong
func filterItems(){ print('filtered!') }
}
How can I add the same Foo method to a UICollectionViewController?
Protocols allow to declare only needed methods signatures, but I need exactly the same method (with body), to avoid copy-paste...
You can use the Protocol Extensions to do what you need. Extensions are new and allow for a default implementation of the protocol methods. I modified your code just a bit so it would compile.
class FilterableTable: FilterType {
init() {}
}
class FilterableCollection: FilterType {
init() {}
}
protocol FilterType {
func filterItems()
}
extension FilterType { // I know this line is wrong
func filterItems(){ print("filtered!") }
}
let a = FilterableTable()
a.filterItems()
let b = FilterableCollection()
b.filterItems()
Check out the section on Protocol Extensions. Swift Programming Guide
Actual answer: Use the Delegates, Luke!
class FilterableTable: UITableViewController {
var filterDelegate: FilterDelegate!
func viewDidLoad(){
filterDelegate = Filter()
}
}
class FilterableCollection: UICollectionViewController {
var filterDelegate: FilterDelegate!
func viewDidLoad(){
filterDelegate = Filter()
}
}
protocol FilterDelegate {
func filterItems()
}
class Filter: FilterDelegate {
func filterItems() {
print("Hooray!")
}
}

Calling protocol default implementation from regular method

I'm wondering if it's possible to achieve such a thing.
I have a Playground like this:
protocol Foo {
func testPrint()
}
extension Foo {
func testPrint() {
print("Protocol extension call")
}
}
struct Bar: Foo {
func testPrint() {
// Calling self or super go call default implementation
self.testPrint()
print("Call from struct")
}
}
let sth = Bar()
sth.testPrint()
I can provide a default implementation in extension but what if Bar needs everything that is in default implementation plus additional things?
It's somehow similar to calling super. methods in classes to fulfill requirement of implementing every property etc. but I see no possibility to achieve the same with structs.
I don't know if you are still looking for an answer to this, but the way to do it is to remove the function from the protocol definition, cast your object to Foo and then call the method on it:
protocol Foo {
// func testPrint() <- comment this out or remove it
}
extension Foo {
func testPrint() {
print("Protocol extension call")
}
}
struct Bar: Foo {
func testPrint() {
print("Call from struct")
(self as Foo).testPrint() // <- cast to Foo and you'll get the default
// function defined in the extension
}
}
Bar().testPrint()
// Output: "Call from struct"
// "Protocol extension call"
For some reason it only works if the function isn't declared as part of the protocol, but is defined in an extension to the protocol. Go figure. But it does work.
Well, you could create a nested type conforming to the protocol, instantiate it, and call the method on that one (it does not matter that you cannot access your type's data as the implementation inside the protocol extension cannot reference it anyway). But it's not a solution I'd call elegant.
struct Bar: Foo {
func testPrint() {
// Calling default implementation
struct Dummy : Foo {}
let dummy = Dummy()
dummy.testPrint()
print("Call from struct")
}
}
what do you think about such way of fixing this ?
protocol Foo {
func testPrint()
}
extension Foo {
func testPrint() {
defaultTestPrint()
}
func defaultTestPrint() {
print("Protocol extension call")
}
}
struct Bar: Foo {
func testPrint() {
// Calling self or super go call default implementation
defaultTestPrint()
print("Call from struct")
}
}
let sth = Bar()
sth.testPrint()
Thanks for the post! If you put the function definition in the protocol then when the object is casted as the protocol it only sees the object's version of the function and since you are calling it inside itself you get the new address of Apple ...
I did try a version like this:
import UIKit
protocol MyProc
{
}
protocol MyFuncProc
{
func myFunc()
}
extension MyProc
{
func myFunc()
{
print("Extension Version")
}
}
struct MyStruct: MyProc, MyFuncProc
{
func myFunc()
{
print("Structure Version")
(self as MyProc).myFunc()
}
}
(MyStruct() as MyFuncProc).myFunc()
This gives an output of:
Structure Version
Extension Version
In case your protocol has associatedType or Self requirements, then the cast will not work. To work around this, create a "shadow" default implementation that both the regular default implementation and the conforming type can call.
protocol Foo {
associatedType Bar
}
extension Foo {
func testPrint() {
defaultTestPrint()
}
}
fileprivate extension Foo { // keep this as private as possible
func defaultTestPrint() {
// default implementation
}
}
struct Bar: Foo {
func testPrint() {
// specialized implementation
defaultTestPrint()
}
}
I have come up with a solution for this.
Issue
When you have a default implementation in an extension, when you implement the protocol to another class/struct, you lose this default implementation if you implement the method. This is by design, this is how protocols work
Solution
Create a Default Implementation of your protocol and make it a property of your protocol.
Then when you implement this protocol in a class, provide your default implementation with a getter
Call default implementation when you need to.
Example
protocol Foo {
var defaultImplementation: DefaultImpl? { get }
func testPrint()
}
extension Foo {
// Add default implementation
var defaultImplementation: DefaultImpl? {
get {
return nil
}
}
}
struct DefaultImpl: Foo {
func testPrint() {
print("Foo")
}
}
extension Foo {
func testPrint() {
defaultImplementation?.testPrint()
}
}
struct Bar: Foo {
var defaultImplementation: DefaultImpl? {
get { return DefaultImpl() }
}
func testPrint() {
if someCondition {
defaultImplementation?.testPrint() // Prints "Foo"
}
}
}
struct Baz: Foo {
func testPrint() {
print("Baz")
}
}
let bar = Bar()
bar.testPrint() // prints "Foo"
let baz = Baz()
baz.testPrint() // prints "Baz"
Drawbacks
You lose the required implementation error in the struct/class where you implement this protocol.

Swift - class method which must be overridden by subclass

Is there a standard way to make a "pure virtual function" in Swift, ie. one that must be overridden by every subclass, and which, if it is not, causes a compile time error?
You have two options:
1. Use a Protocol
Define the superclass as a Protocol instead of a Class
Pro: Compile time check for if each "subclass" (not an actual subclass) implements the required method(s)
Con: The "superclass" (protocol) cannot implement methods or properties
2. Assert in the super version of the method
Example:
class SuperClass {
func someFunc() {
fatalError("Must Override")
}
}
class Subclass : SuperClass {
override func someFunc() {
}
}
Pro: Can implement methods and properties in superclass
Con: No compile time check
The following allows to inherit from a class and also to have the protocol's compile time check :)
protocol ViewControllerProtocol {
func setupViews()
func setupConstraints()
}
typealias ViewController = ViewControllerClass & ViewControllerProtocol
class ViewControllerClass : UIViewController {
override func viewDidLoad() {
self.setup()
}
func setup() {
guard let controller = self as? ViewController else {
return
}
controller.setupViews()
controller.setupConstraints()
}
//.... and implement methods related to UIViewController at will
}
class SubClass : ViewController {
//-- in case these aren't here... an error will be presented
func setupViews() { ... }
func setupConstraints() { ... }
}
There isn't any support for abstract class/ virtual functions, but you could probably use a protocol for most cases:
protocol SomeProtocol {
func someMethod()
}
class SomeClass: SomeProtocol {
func someMethod() {}
}
If SomeClass doesn't implement someMethod, you'll get this compile time error:
error: type 'SomeClass' does not conform to protocol 'SomeProtocol'
Another workaround, if you don't have too many "virtual" methods, is to have the subclass pass the "implementations" into the base class constructor as function objects:
class MyVirtual {
// 'Implementation' provided by subclass
let fooImpl: (() -> String)
// Delegates to 'implementation' provided by subclass
func foo() -> String {
return fooImpl()
}
init(fooImpl: (() -> String)) {
self.fooImpl = fooImpl
}
}
class MyImpl: MyVirtual {
// 'Implementation' for super.foo()
func myFoo() -> String {
return "I am foo"
}
init() {
// pass the 'implementation' to the superclass
super.init(myFoo)
}
}
You can use protocol vs assertion as suggested in answer here by drewag.
However, example for the protocol is missing. I am covering here,
Protocol
protocol SomeProtocol {
func someMethod()
}
class SomeClass: SomeProtocol {
func someMethod() {}
}
Now every subclasses are required to implement the protocol which is checked in compile time. If SomeClass doesn't implement someMethod, you'll get this compile time error:
error: type 'SomeClass' does not conform to protocol 'SomeProtocol'
Note: this only works for the topmost class that implements the protocol. Any subclasses can blithely ignore the protocol requirements. – as commented by memmons
Assertion
class SuperClass {
func someFunc() {
fatalError("Must Override")
}
}
class Subclass : SuperClass {
override func someFunc() {
}
}
However, assertion will work only in runtime.
This is what I usually do, to causes the compile-time error :
class SuperClass {}
protocol SuperClassProtocol {
func someFunc()
}
typealias SuperClassType = SuperClass & SuperClassProtocol
class Subclass: SuperClassType {
func someFunc() {
// ...
}
}
You can achieve it by passing function into initializer.
For example
open class SuperClass {
private let abstractFunction: () -> Void
public init(abstractFunction: #escaping () -> Void) {
self.abstractFunction = abstractFunction
}
public func foo() {
// ...
abstractFunction()
}
}
public class SubClass: SuperClass {
public init() {
super.init(
abstractFunction: {
print("my implementation")
}
)
}
}
You can extend it by passing self as the parameter:
open class SuperClass {
private let abstractFunction: (SuperClass) -> Void
public init(abstractFunction: #escaping (SuperClass) -> Void) {
self.abstractFunction = abstractFunction
}
public func foo() {
// ...
abstractFunction(self)
}
}
public class SubClass: SuperClass {
public init() {
super.init(
abstractFunction: {
(_self: SuperClass) in
let _self: SubClass = _self as! SubClass
print("my implementation")
}
)
}
}
Pro:
Compile time check for if each subclassimplements the required method(s)
Can implement methods and properties in superclass
Note that you can't pass self to the function so you won't get memory leak.
Con:
It's not the prettiest code
You can't use it for the classes with required init
Being new to iOS development, I'm not entirely sure when this was implemented, but one way to get the best of both worlds is to implement an extension for a protocol:
protocol ThingsToDo {
func doThingOne()
}
extension ThingsToDo {
func doThingTwo() { /* Define code here */}
}
class Person: ThingsToDo {
func doThingOne() {
// Already defined in extension
doThingTwo()
// Rest of code
}
}
The extension is what allows you to have the default value for a function while the function in the regular protocol still provides a compile time error if not defined