Swift override function in extension

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?


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.


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()
    }
}