Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding non-@objc declarations from extensions is not supported

Tags:

ios

swift

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 }  } 
like image 472
michaeldebo Avatar asked Mar 26 '19 18:03

michaeldebo


Video Answer


1 Answers

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()) 
like image 60
Josh Homann Avatar answered Sep 20 '22 12:09

Josh Homann