ArtistVC is a subclass of CategoryVC which is a subclass of BrowserVC.
Most of ArtistVC's UITableView Data Source methods wind up calling CategoryVC's implementation of those methods with return super.tableView(tableView, cellForRowAt: adjustedIndexPath)(for example), after some other things happen of course, like modifying the indexPath passed to the method.
But sometimes I actually want to bypass CategoryVC's implementation and use BrowserVC's implementation.
super.super.someMethod() apparently isn't the answer. Is this possible?
There's a (convoluted) way to do this but it requires that the intermediate class "contributes" to the bypassing of its override.
For example:
class A
{
func doIt(_ parameter:Int) { print("A.doIt(\(parameter))") }
}
class B:A
{
override func doIt(_ parameter:Int) { print("B.doIt(\(parameter))") }
var super_doIt:(Int)->() { return super.doIt }
}
class C:B
{
override func doIt(_ parameter:Int)
{ super.super_doIt(parameter) }
}
let c = C()
c.doIt(3) // A.doIt(3)
Related
This question already has answers here:
In Swift, how do I have a UIScrollView subclass that has an internal and external delegate?
(4 answers)
Closed 4 years ago.
Given a very simple protocol :
protocol TheProtocol {
func doSomething()
func doSomethingElse()
func doThis()
func doThat()
}
I have a class Base that has a delegate waiting to be set.
// Can't modify this class at all
class Base {
public var delegate: TheProtocol?
}
My second class B inherits from this class Base, and implements TheProtocol in order to set the delegate to itself.
class B: Base, TheProtocol {
override init() {
super.init()
self.delegate = self
}
func doSomething() {
}
func doSomethingElse() {
}
... other methods to implement
}
Now what I want to be able to do, is to have a last class C, that contains an instance of B, and also set the delegate. I want the delegate to work both inside B and C.
The major constraint is that I can't modify the Base class.
class C: TheProtocol {
var obj = B()
init() {
// If I do this it won't fire within B anymore
obj.delegate = self
}
func doSomething() {
}
func doSomethingElse() {
}
... other methods to implement
}
It is actually possible using a Proxy delegate. However not really recommended.
In Swift, how do I have a UIScrollView subclass that has an internal and external delegate?
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!")
}
}
So I was thinking about a custom pattern in my project, but I can't get it to work. The main idea is to change the typealias on every subclass to get access to the subclass specific interface.
protocol InstanceInterface: class {
typealias Interface
var interface: Interface { get }
}
// Baseclass
protocol FirstClassInterface: class { /* nothing here for the example */ }
class FirstClass: InstanceInterface, FirstClassInterface {
typealias Interface = FirstClassInterface
var interface: Interface { return self }
}
// Subclass
protocol SecondClassInterface: FirstClassInterface {
func foo()
}
class SecondClass: FirstClass, SecondClassInterface {
typealias Interface = SecondClassInterface // <--- This does nothing :(
func foo() { print("hello world") } // Swift 2.0 here
}
// Lets say I want to call foo trough the interface
let test = SecondClass()
test.interface.foo() // 'Interface' does not have a member named 'foo'
Is there something I'm doing wrong or do I misunderstand some Swift concepts here?! I do need to subclass here to not to implement everything from super class' protocols over and over again. Is my little pattern even possible? I'd appreciate any help. :)
Would something like this work for your purposes?
class MyClass<T> {
}
class MySubclass1: MyClass<String> {
}
class MySubclass2: MyClass<Int> {
}
Unfortunately there is no good workaround for this problem.
The main idea to override the typealias would work in this case but consider the following:
protocol TakeAndGet {
typealias T
func take(value: T)
func get() -> T
}
class FirstClass: TakeAndGet {
typealias T = FirstClass
var property = 0
func take(value: T) {
value.property = 4
}
func get() -> T {
return FirstClass()
}
}
class SecondClass: FirstClass {
typealias T = SecondClass
var property2 = "hello"
}
If the typealias of the SecondClass overrides the other one the take method would work since it takes a subclass which can be treated as the superclass. But the get method cannot implicitly convert FirstClass to SecondClass. Therefore it is not possible to override a typealias.
Now if we want to override the get function with get() -> SecondClass it wouldn't work since it has not the same signature as the one in the superclass. In addition we inherit the get method which results in an ambiguous use:
SecondClass().get() // which type gets returned? SecondClass or FirstClass
So you have to try a different approach.
I’ve got a Swift class Parent that has a method doSomething() and I want to detect (in Parent) if a subclass has overridden doSomething(). How do I do that?
class Parent {
func doSomething() {}
func subclassOverridesDoSomething() -> Bool {
// what goes here?
return true
}
}
class Child: Parent {
override func doSomething() {}
}
I know I can do this with NSObject or even the Objective C runtime functions, but how can I do it with Swift classes?
You can use the Objective-C runtime provided you expose the function with dynamic:
class Parent {
func doSomething() {}
func subclassOverridesDoSomething(t:Parent.Type) -> Bool {
let originalMethod = class_getInstanceMethod(t, "doSomething")
return originalMethod != nil
}
}
class Child: Parent {
dynamic override func doSomething() {}
}
Parent().subclassOverridesDoSomething(Child.self)
If you omit dynamic, it won't work because Objective-C can't see the method.
Well Swift doesn't really offer methods to do that.
Also in my opinion, there is no disadvantage in using Objective-c methods like method_getImplementation or the NSObject. You will have to use the methods objective-c offers you to solve your problem.
For example:
let selector = Selector("viewWillAppear:")
let originalMethod = class_getInstanceMethod(YourClass, selector)
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