7

If I have a class:

class Spaceship<FuelType> {
    function prepareForLiftoff() throws {
        //Start the countdown!
    }
}

I originally assumed that I would be able to override prepareForLiftoff without subclassing by adding an extension:

extension Spaceship where FuelType: CollectionType {
    func prepareForLiftoff() throws {}
} 

This code doesn't compile though, the error says invalid redeclaration of the function, which makes sense.

My question is: Is there anyway to override a function of a particular class? In other words can I replace the functionality under certain conditions like the example above where FuelType: CollectionType. If not, is there any other workaround or way to achieve that behavior (maybe declaring another protocol, idk)

Now that I think about it more, I would have to say that's not possible because what's to stop someone from overriding any of the standard library functions?

barndog
  • 6,975
  • 8
  • 53
  • 105

2 Answers2

24

From the documentation:

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

The documentation lists carefully and precisely what an extension is allowed to do.

As to your question:

Is there anyway to override a function of a particular class

Yes, it's called subclassing.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    Fair enough, I had my fingers crossed. – barndog Nov 23 '15 at 02:50
  • 1
    How would one override a function of a `struct`? – BallpointBen Jun 21 '17 at 14:28
  • @matt: Do you have an idea why overriding in an extension in a *different framework* is possible: https://stackoverflow.com/questions/46123963/redeclaring-members-in-an-extension-hides-the-original-member-sometimes-why ? – Martin R Sep 13 '17 at 15:07
  • @MartinR https://bugs.swift.org/browse/SR-3228 and https://bugs.swift.org/browse/SR-2935 – matt Sep 13 '17 at 16:10
  • @matt: Thanks! – (I wonder a bit why SR-3228 is closed as a duplicate of SR-2935, the latter seems to be specific about overriding Objective-C methods, but that is not important to me at present.) – Martin R Sep 13 '17 at 16:17
  • You can override a function of a parent class in an extension. The question is if you should. – Au Ris Dec 16 '19 at 13:41
2

Instead of overriding, you may like to try swizzling. For example the following code allows you to run your own viewWillAppear. Swift 3:

extension UIViewController {
    open override class func initialize() {
        // make sure this isn't a subclass
        guard self === UIViewController.self else { return }
        DispatchQueue.once(token: "viewWillAppear") {
            let originalSelector = #selector(self.viewWillAppear(_:))
            let swizzledSelector = #selector(self.proj_viewWillAppear1(animated:))
            let originalMethod = class_getInstanceMethod(self, originalSelector)
            let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }

    func proj_viewWillAppear1(animated: Bool) {
        self.proj_viewWillAppear1(animated: animated)
        let viewControllerName = NSStringFromClass(type(of: self))
        print("viewWillAppear: \(viewControllerName)")
    }
}

Update 20170621

public extension DispatchQueue {
    private static var _onceTracker = [String]()

    public class func once(file: String = #file, function: String = #function, line: Int = #line, block:(Void)->Void) {
        let token = file + ":" + function + ":" + String(line)
        once(token: token, block: block)
    }

    public class func once(token: String, block:(Void)->Void) {
        objc_sync_enter(self)
        defer { objc_sync_exit(self) }

        if _onceTracker.contains(token) {
            return
        }

        _onceTracker.append(token)
        block()
    }
}
superarts.org
  • 7,009
  • 1
  • 58
  • 44
  • Hi, can i make this work now? there is no DispatchQueue.once. thanks – ilan Jun 21 '17 at 06:56
  • @ilan sure you can create an extension like the one I added, or come up with your own version of implementation. – superarts.org Jun 21 '17 at 20:11
  • 1
    You shouldn't swizzle generally speaking – barndog Jun 12 '18 at 16:13
  • I'm with @barndog. Swizzling should be avoided at all costs.There's a better than even chance Apple will not allow swizzled apps in the App Store starting with iOS 14. – David Nedrow Nov 01 '18 at 21:27
  • I totally agree with you guys, but I was just providing a solution to address the specific technical question from OP. Generally speaking, even subclassing should not be used widely as composition is always above inheritance. But IMO stackoverflow is not the place that you just throw SOLID principles and protocol oriented programming onto others face and let them learn how to code properly; a question was asked, and a solution has been given, and that's it. – superarts.org Nov 02 '18 at 01:14