Swift: type must implement protocol and be a subclass of given class
You can do it like this:
protocol SomeProtocol {
func someMethodInSomeProtocol()
}
class SomeType { }
class SomeOtherType: SomeType, SomeProtocol {
func someMethodInSomeProtocol() { }
}
class SomeOtherOtherType: SomeType, SomeProtocol {
func someMethodInSomeProtocol() { }
}
func someMethod<T: SomeType where T: SomeProtocol>(condition: Bool) -> T {
var someVar : T
if (condition) {
someVar = SomeOtherType() as T
}
else {
someVar = SomeOtherOtherType() as T
}
someVar.someMethodInSomeProtocol()
return someVar as T
}
This defines a function that returns an object of type 'SomeType' and protocol 'SomeProtocol' and returns an object that adheres to those conditions.
Protocol inheritance from class?
Implemented In Swift 5: From the Swift 5 Release notes
Protocols can now constrain their conforming types to those that subclass a given class. Two equivalent forms are supported:
protocol MyView: UIView { /*...*/ }
protocol MyView where Self: UIView { /*...*/ }
See this tweet by John Sundell, showing a possible use case
Forced to cast, even if protocol requires given type
Adopting the protocol Fooable
tells the compiler that this particular UIViewController
responds to foo()
, no less no more.
In reverse conclusion Fooable
does not become UIViewController
necessarily.
The constraint Self: UIViewController
is just another information for the compiler to complain at compile time if the affected class is not UIViewController
In your case when annotating SampleViewController
to Fooable
the compiler knows only that SampleViewController
responds to foo()
. It does not know that the type is actually a subclass of UIViewController
.
So do not annotate a concrete class to a protocol if you want to access properties of the concrete class.
However you could add the show
method and other common properties / methods to the protocol
protocol Fooable: class where Self: UIViewController {
func foo()
func show(_ vc: Fooable, sender: Any?)
}
then you can use Fooable
because the compiler knows that the type adopting the protocol responds to the method.
A suitable practice to annotate a type to a protocol is for example when you are going to create a heterogenous but restricted collection type
let array : [CustomStringConvertible] = ["Foo", 1, false]
array.forEach{ print("\($0)")}
The code prints the three items using the description
property which all items respond to. The compiler recognizes the three items as types which have a description
property, not as String
, Int
and Bool
.
Update:
In Swift 5 support of superclass constrained protocols is implemented.
How a generic class to conform a protocol (that have init in it) with constraint?
I don't know of a way to achieve this without making Graph final
. If you do make it final
, however, it will work fine as long as you remove required
(required
doesn't mean anything if there can't be subclasses):
extension Graph: ExpressibleByArrayLiteral where D == Int {
convenience init(arrayLiteral elements: Node...) {
self.init(Array(zip(0..., elements)))
}
}
Swift protocol with where Self clause
The ability to put superclass constraints on protocols declarations (that is, being able to define protocol P where Self : C
where C
is the type of a class) was a premature consequence of
SE-0156, and the syntax should have been rejected in Swift 4.x until the feature was implemented. Attempting to use this feature in Swift 4.x can cause miscompilation and crashes, so I would avoid using it until Swift 5.
In Swift 5 (Xcode 10.2) the feature has now been implemented. From the release notes:
Protocols can now constrain their conforming types to those that
subclass a given class. Two equivalent forms are supported:protocol MyView: UIView { /*...*/ }
protocol MyView where Self: UIView { /*...*/ }
Swift 4.2 accepted the second form, but it wasn’t fully implemented
and could sometimes crash at compile time or runtime. (SR-5581)
(38077232)
This syntax places a superclass constraint on MyView
which restricts conforming types to those inheriting from (or being) UIView
. In addition, the usage of MyView
is semantically equivalent to a class existential (e.g UIView & MyView
) in that you can access both members of the class and requirements of the protocol on the value.
For example, expanding upon the release notes' example:
protocol MyView : UIView {
var foo: Int { get }
}
class C : MyView {} // error: 'P' requires that 'C' inherit from 'UIView'
class CustomView : UIView, MyView {
var foo: Int = 0
}
// ...
let myView: MyView = CustomView(frame: .zero)
// We can access both `UIView` members on a `MyView` value
print(myView.backgroundColor as Any)
// ... and `MyView` members as usual.
print(myView.foo)
Swift -- Require classes implementing protocol to be subclasses of a certain class
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).
Implementing Swift protocol methods in a base class
This should work:
protocol MyProtocol {
class func retrieve(id:String) -> Self?
}
class MyBaseClass: MyProtocol {
required init() { }
class func retrieve(id:String) -> Self? {
return self()
}
}
required init() { }
is necessary to ensure any subclasses derived from MyBaseClass
has init()
initializer.
Note that this code crashes Swift Playground. I don't know why. So try with real project.
Related Topics
Encryption with Rsa Public Key on iOS
Set Delegates to Nil Under Arc
Generating Custom Thumbnail from Alassetrepresentation
Easiest Way of Getting Reverse Geocoded Current Location from iOS
Uitableview Invoke Swipe Actions Programmatically
Xcode 8 Gm Seed Storyboard Layout Issue
Get Average Color of Uiimage in Swift
Strong Reference to a Weak References Inside Blocks
How to Move to the Next Page in Facebook JSON Response Using iOS Sdk
Swiftui Transitions: Scale from Some Frame - Like iOS Homescreen Is Doing When Opening an App
Why Are Animations on Bounds of an Uilabel Only Working When Increasing the Size
Uilabel: Background Dependent Color
Check If an Auto-Renewable Subscription Is Still Valid
Unknown Class in Interface Builder
iOS Swift Converting Calendar Component Int Month to Medium Style String Month
How to Pop View Controller to One of the Previous View Controllers in Swift