31

Seemingly out of nowhere I started getting hundreds of errors associated with two extension functions that I use frequently.

I tried commenting out all the new code that preceding this error showing up. I also tried cleaning my build folder. How do I get ride of the error found in the title of this post? Why did it randomly appear when I've been using these extensions successfully for months?

extension UITableViewCell {

public func getSize(large: CGFloat, medium: CGFloat, small: CGFloat) -> CGFloat {
    var size = CGFloat()
    let screenHeight = Int(UIScreen.main.bounds.height)
    if screenHeight >= 800 {
        size = large
    } else if screenHeight >= 600 {
        size = medium
    } else {
        size = small
    }
    return size
}

public func formatPrice(_ price: Int) -> String {
    let lastDigit = price % 10
    var stringPrice = ""
    if lastDigit == 0 {
        stringPrice = "$\(Double(price) / 100)0"
    } else {
        stringPrice = "$\(Double(price) / 100)"
    }
    return stringPrice
}

}
michaeldebo
  • 3,065
  • 4
  • 14
  • 20
  • 1
    Did you update your xcode version? Did you change swift versions? – Mocha Mar 26 '19 at 18:53
  • 4
    Can you give us [reproducible example](https://stackoverflow.com/help/mcve)? Put this code in a blank project and it won’t reproduce the problem. So figure out what you need to add from your project to manifest the problem. Or go from the other direction, make copy of your project and rip out everything unrelated to the problem until you figure out what is needed to reproduce it. The only way I can think of reproducing it is to define `UITableViewCell` subclass which implements these two methods. But you would have mentioned that... – Rob Mar 26 '19 at 18:58
  • 1
    I started getting this issue when I upgraded from Xcode 11.6 to 12.0. Swift version 4.2. – Nathan Dudley Sep 22 '20 at 21:55

1 Answers1

63

If you add functions to a class in an extension (ie they are not in the class definition) then those methods are statically dispatched in swift because the compiler cannot add the methods to the class's vtable (ie the vtable needs to be made at compile time, but you can add an extension later, such as in another module). This is why the compiler is complaining that you cannot override the methods (ie they are non virtual).

Objective C dispatch works differently, via the selector table and it can be modified even at run time. Thats why the compiler says use @objc and sure enough if you do this it will work.

EXAMPLE:

This does not compile because we are trying to override and dynamically dispatch a statically dispatched non virtual function in swift

extension UITableViewCell {
    func a() {
        print("UITableViewCell")
    }
}

class B: UITableViewCell {
    override func a() {
        print("B")
    }
}

let b = B()
print(b.a())

This works and it prints "B" because its using objc selector dispatch

import UIKit
import PlaygroundSupport

extension UITableViewCell {
    @objc func a() {
        print("UITableViewCell")
    }
}

class B: UITableViewCell {
    override func a() {
        print("B")
    }
}

let b = B()
print(b.a())
Josh Homann
  • 15,933
  • 3
  • 30
  • 33
  • 1
    Tx. But adding a little more info: If your override super class delares the func in its main declaration but the subclass does so in an extension you get: `Cannot override a non-dynamic class declaration from an extension`. See https://stackoverflow.com/q/43087698/826946 – Andy Weinstein May 17 '20 at 12:26