Swift -- Require classes implementing protocol to be subclasses of a certain class
Solution 1
I think you are after a subclass of NSView
. Try this:
protocol TransmogrifiableView {
func transmogrify()
}
class MyNSView: NSView, TransmogrifiableView {
// do stuff.
}
And later in the code accept objects of type MyNSView
.
Edit
You maybe want an Extension
, see this
extension NSView: TransmogrifiableView {
// implementation of protocol requirements goes here
}
- Note that you will not be able to get an NSView without this extra method.
- You can separately extend subclasses of NSView to override this new method.
Yet another option is to make a class which holds a pointer to an NSView, and implements additional methods. This will also force you to proxy all methods from NSView that you want to use.
class NSViewWrapper: TransmogrifiableView {
var view : NSView!
// init with the view required.
// implementation of protocol requirements goes here.
.....
// proxy all methods from NSView.
func getSuperView(){
return self.view.superView
}
}
This is quite long and not nice, but will work. I would recommend you to use this only if you really cannot work with extensions (because you need NSViews without the extra method).
Solution 2
Update. In the latest Swift version you can just write
protocol TransmogrifiableView: NSView {
func transmogrify()
}
, and this will enforce the conformer types to be either NSView
, or a subclass of it. This means the compiler will "see" all members of NSView
.
Original answer
There is a workaround by using associated types to enforce the subclass:
protocol TransmogrifiableView {
associatedtype View: NSView = Self
func transmogrify()
}
class MyView: NSView, TransmogrifiableView { ... } // compiles
class MyOtherClass: TransmogrifiableView { ... } // doesn't compile
Solution 3
Starting from Swift 4 you can now define this as followed:
let myView: NSView & TransmogrifiableView
For more information, checkout issue #156 Subclass Existentials
Solution 4
You could use something like this:
protocol TransmogrifiableView where Self:NSView {}
This requires all created instances which one conforms to TransmogrifiableView protocol to be subclassed with NSView
Solution 5
As per definition a protocol just declares requirements of "methods, properties an other requirements". And by "other requirements" it means a superclass is not a part of it.
A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality.
Right now, I don't see a clean solution. It's possible to use a where
-clause to define a type which is a NSView
and conforms to the TransmogrifiableView
like this:
class MyClass<T where T: NSView, T: TransmogrifiableView> {
var aTransmogrifiableNSView: T
}
Or you could use another superclass:
protocol TransmogrifiableViewProtocol {
func transmogrify()
}
class TransmogrifiableView: NSView, TransmogrifiableViewProtocol {
func transmogrify() {
assert(false, "transmogrify() must be overwritten!")
}
}
class AnImplementedTransmogrifiableView: TransmogrifiableView {
func transmogrify() {
println("Do the transmogrification...")
}
}
In the end both solutions aren't clean and wouldn't satisfy myself. Maybe an abstract
-keyword will be added to Swift someday?
exists-forall
Student of Computer Science and Mathematics at UC Berkeley.
Updated on June 02, 2022Comments
-
exists-forall about 2 years
I'm creating several
NSView
classes, all of which support a special operation, which we'll calltransmogrify
. At first glance, this seems like the perfect place for a protocol:protocol TransmogrifiableView { func transmogrify() }
However, this protocol does not enforce that every
TransmogrifiableView
be anNSView
as well. This means that anyNSView
methods I call on aTransmogrifiableView
will not type check:let myView: TransmogrifiableView = getTransmogrifiableView() let theSuperView = myView.superView // error: TransmogrifiableView does not have a property called 'superview'
I don't know how to require that all classes implementing my protocol are also subclasses of
NSView
. I tried this:protocol TransmogrifiableView: NSView { func transmogrify() }
but Swift complains that protocols cannot inherit from classes. It does not help to turn the protocol into a class-only protocol using
protocol TransmogrifiableView: class, NSView { func transmogrify() }
I cannot make
TransmogrifiableView
a superclass rather than a protocol, because some of myTransmogrifiableView
classes must be subclasses of other, non-transmogrifiable views.How should I require that all
TransmogrifiableView
's also beNSView
's? I really don't want to pepper my code with "as
" conversions, which are bad form and distracting.