64

I have an extension:

public extension UIWindow {
    override public func topMostController()->UIViewController? { ... }
}

but for my topMostController I get the next error:

Declarations in extensions cannot override yet error

It works well for Swift 3.1, but for Swift 4 I get this error. How can it be fixed? What did they change in Swift 4?

nathan
  • 9,329
  • 4
  • 37
  • 51
J. Doe
  • 683
  • 1
  • 5
  • 7
  • 2
    According to this [very related question](https://stackoverflow.com/questions/38213286/overriding-methods-in-swift-extensions), overriding functions in Swift extensions isn't an encouraged thing. – Michael Dautermann Jun 18 '17 at 15:18
  • 4
    Mark the function with @objc: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170102/029909.html – nathan Aug 02 '17 at 04:30
  • 1
    I'm getting this bug not when writing the override in an extension, but when I'm overriding a function that was declared in an extension, and that is where I want that function. – ScottyBlades Aug 29 '17 at 18:11
  • giving @objc has not solved the problem – Gorib Developer Aug 01 '18 at 11:33

3 Answers3

66

It will work if you make the base implementation @objc. See Hamish's answer for a detailed explanation about the internals.

Overriding methods declared in extensions is a bit tricky to do correctly. Objective-C supports it, but it's not absolutely safe. Swift aims to do it better. The proposal is not completed yet.

Current version of the proposal available here.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • 1
    I have just tested it on Swift 4 project it worked ! – MBH Oct 23 '17 at 18:13
  • I guess if it's visible in objc it can be handled in runtime. This kind of stuff may be correct in a way, but hell: Swift is becoming as ugly as objc... – brainray Feb 13 '18 at 21:27
  • you mean just add `@objc` *before* `override public func topMostController()->UIViewController`? – mfaani Jun 12 '18 at 15:30
12

Extensions can add new functionality to a type, but they cannot override existing functionality.

Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling).

Extensions in Swift can:

  • Add computed instance properties and computed type properties
  • Define instance methods and type methods
  • Provide new initializers
  • Define subscripts
  • Define and use new nested types
  • Make an existing type conform to a protocol

Apple Developer Guide

You are trying to do is similar to what done by this code:

class MyClass: UIWindow {
    func myFunc() {}
}

extension MyClass {
    override func myFunc() {}
}

NOTE: If you want to override topMostController() then make subclass of UIWindow

Nikhlesh Bagdiya
  • 4,316
  • 1
  • 19
  • 29
3

Swift 5

Actually there are few problems in OP code:

  1. UIView (which is superclass of UIWindow) doesn't have method topMostController(), that why you can't override it.

  2. Apple doesn't encourage override func inside extension:

    Extensions can add new functionality to a type, but they cannot override existing functionality.

  3. Incase you still want to override function in extension, there are 2 ways:

[A] Mark your function with @objc dynamic func in parent class:

class Vehicle {
    @objc dynamic func run() { /* do something */ }
}

class Car: Vehicle { }

extension Car {
    override func run() { /* do another thing */ }
}

[B] Override function from build-in classes, which is descendant of NSObject.

 extension UIWindow {
    // UIWindow is a descendant of NSObject, and its superclass UIView has this function then you can override
    override open func becomeFirstResponder() -> Bool {
        ...
        return super.becomeFirstResponder()
    }
 }
nahung89
  • 7,745
  • 3
  • 38
  • 40