devios1
devios1

Reputation: 38025

Can a Swift class be extended multiple times with the same methods?

I am designing a framework that uses protocols and extensions to allow for third-parties to add support for my framework to their existing classes.

I'd also like to include some built-in extensions for known classes like UIView, but I don't want to prevent users from defining their own additional support for the same classes.

My question is is there any way that I can extend the same class twice, and override the same (protocol) method in that class both times, while still having some way to call the other if the first one fails.

Elaboration: I really have three goals here I want to achieve:

  1. I want to allow users of my framework to provide their own extensions for their own (or any) UIView subclasses.
  2. I also need some way to allow general behavior that can apply to all UIViews as a fallback option (i.e. if the specific class extension can't handle it, fall back on the generic UIView extension).
  3. I'd also like to separate out my own implementation, by providing some built-in generic view handling, but in such a way that it doesn't prevent third parties from also defining their own additional generic handling. (If I can't do this, it's not a big deal, the first two parts are the most important.)

I have part 1 working already. The problem is how to get this fallback behavior implemented. If I do it all with extensions, the subclass will override the superclass's implementation of the protocol method. It could call super.method, but I'd like to avoid putting that responsibility on the subclass (in case the author forgets to call super).

I'd like to do this all from the framework code: first, call the object's protocol method. If it returns false, I'd like to somehow call the generic UIView handler.

Now that I'm typing it all out, I'm wondering if I can just use a different method for the generic fallback and be done with it. I just figured it would be elegant if I could do it all with one method.

Upvotes: 2

Views: 4292

Answers (3)

mfaani
mfaani

Reputation: 36297

No! It can't be extended multiple times.

extension Int {
    var add: Int {return self + 100} // Line A
}

extension Int {
    var add: Int {return self + 105} //Line B
}

Doing so would create a compile time error ( on Line B) indicating: Invalid redeclaration of 'add'

Swift is a static typing language and helps you find these sorts of errors before runtime


In Objective-C you can write this and still not get an error, however the result would be undefined, because you wouldn't know which method gets loaded first during runtime.

Upvotes: 3

DerrickHo328
DerrickHo328

Reputation: 4886

I realize this Question is over a year old and the original poster has probably moved on to other things, but I'd like to share an idea anyways and perhaps get some feedback.

You say that you want a method that can be overwritten multiple times. The short answer, like many in this thread have given is no, but the long answer is yes.

We can solve the issue with a bit of generic magic.

class MyView: UIView {
    var customizer: MyProtocol<MyView> = Defaults()

    func willCallCustomizer() {
        customizer.coolMethod(self)
    }
}

// Use this class as if it were a protocol
class MyProtocol<T: UIView>: NSObject {
    func coolMethod(_ view: T) {}
}

// Class inherits from the "protocol" 
class Defaults: MyProtocol<MyView> {
    override func coolMethod(_ view: MyView) {
        // Some default behavior
    }
}

/// on the clients end...

class CustomerCustomizer: MyProtocol<MyView> {
    override func coolMethod(_ view: MyView) {
        // customized behavior
    }
}

So if the client wants to use their own customizer they can just set it, otherwise it will just use the default one.

myViewInstance.customizer = CustomerCustomizer()

The benefit of this approach is that the client can change the customizer object as many times as they want. Because MyProtocol is generic, it may be used for other UIView's as well; thus fulfilling the role of a protocol.

Upvotes: 1

mc01
mc01

Reputation: 3770

Overriding a single protocol method twice in 2 separate extensions wouldn't work, because the protocol method names would collide. Once compiled, they're all just methods on the same class. With that in mind, perhaps put all the protocol methods in their own extension & call them from within the other ones?

The following could be one general option. Could get messy if you decide to keep adding additional extension functionality.

    class baseClass {
           //stuff
    }

    extension baseClass: myProtocol {

        override func myProtocolMethod(args) -> returnType {
           //Repeat this in a separate extension & your method names collide     
            var status: Bool

          //protocol method code sets status as appropriate... 

          return status = true ? optOne(status) : optTwo(status)                 

        }

        func optOne(status:Bool) -> returnType{
            //do the 'true' thing
            return returnType
        }

        func optTwo(status:Bool) -> returnType{
            //do the 'false' thing
            return returnType
        }
    } 

    extension baseClass {
        var oneExtension = myProtocolMethod(someArg)
    }

    extension baseClass {
        var twoExtension = myProtocolMethod(someArg)
    }

Upvotes: 2

Related Questions