5

I am working on iOS app which is having Obj C code as well as Swift. I am migrating my existing Objective C category to swift code. But when I override existing method in swift extension, it is not compiling. Swift extension is working well for new methods but not for overriding existing methods.

Code:

extension UIViewController {


   public override func shouldAutorotate() -> Bool {
        return false
    }

    public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.Portrait
    }


}

Error:

 Method 'shouldAutorotate()' with Objective-C selector 'shouldAutorotate' conflicts with previous declaration with the same Objective-C selector

 Method does not override any method from its superclass

 Method 'supportedInterfaceOrientations()' with Objective-C selector 'supportedInterfaceOrientations' conflicts with previous declaration with the same Objective-C selector

Here, Am I missing anything?

I am using Xcode 7.3.1 and Swift 2.x

EDIT:

From below Answers, I got to know that We cant change behaviour of existing method of class at runtime in Swift extension like in Objective C Categories. Here I should make a base class which will override method and I should use all my ViewControllers as child classes from new base class as parent.

But in my case, I want to change behaviour of all "shouldAutorotate" methods including 3rd party frameworks UIViewController. In above case I cant force all third party frameworks UIviewControllers to become subclass of my base class. In Objective C i could achieve this.

Swapnil
  • 1,858
  • 2
  • 22
  • 49

1 Answers1

7

Swift extensions aren't to be used to override methods declared in the class they're extending – especially for Objective-C classes, that's very much like providing two definitions of the same method in the same class. Imagine seeing a class that looked like:

class UIViewController : UIResponder {
    public func shouldAutorotate() -> Bool {
        return true
    }
    public func shouldAutorotate() -> Bool {
        return false
    }
}

Which one wins? That's the conflict you're being warned about.

If you need to override methods for a view controller of yours, you'll need to do that in a subclass, not an extension.

Ninja edit: this may have been possible to do in Objective-C, but was a programming error there. If a category duplicates a method from a main class, which definition gets used is undefined. See this SO post and the backing Apple documentation.

Community
  • 1
  • 1
Tim
  • 59,527
  • 19
  • 156
  • 165
  • So in that case, In swift extension. We will not be able to change behaviour of existing method of class at runtime without subclassing? – Swapnil Jun 08 '16 at 15:45
  • 1
    Correct – if you want to change the behavior of the class in this way, subclass it. This keeps your code from affecting any UIViewController instances that Apple is using, for example. – Tim Jun 08 '16 at 15:57
  • Then how should we achieve this in swift? I want to change behaviour of all "shouldAutorotate" methods including 3rd party frameworks UIViewController. In above case I cant force all third party frameworks UIviewControllers to become sublcass of my base class. In Objective C i could achieve this. – Swapnil Jun 08 '16 at 17:30
  • Updated in Question – Swapnil Jun 08 '16 at 17:38
  • The short answer is that you shouldn't. Apple and third-party frameworks might have their own particular notions of how methods (including `shouldAutorotate`) should be implemented for their controllers, and it's not usually a good idea to override them. Is there an underlying problem you're trying to solve? If you need to turn off rotation for your entire app, for example, you can do that by restricting orientation support in your project's settings/`Info.plist` file. – Tim Jun 08 '16 at 20:24
  • Yes I completely agree with you. Yes I was trying to fix bug in 3rd party framework by this way and I succeeded through Objective C. Only one UIviewController, I want to be in "LandScape" and other should be in "Portrait". Now I don't have code for that specific view controller, which is forcing me this to do it at run time. (By adding ugly class name check in rotation API) – Swapnil Jun 08 '16 at 20:32