I have a protocol for which I want to provide default functionality in the case that the conforming class is either ClassA OR ClassB. Is it possible to use || in a protocol extension where clause? I've tried the following but it doesn't work:
extension Protocol where Self: ClassA || Self: ClassB {
func method() {
// implementation if conforming class is ClassA OR ClassB
}
}
No, you cannot use || (or something equivalent) in the where clause of a protocol extension.
If the extension method needs certain functionality which is present in both ClassA and ClassB then you can define that in a protocol (to which both classes conform), and constrain the extension to that protocol.
It's simply not possible at the moment. One solution could be creating two different extensions.
extension Protocol where Self: ClassA {
func method() {
commonMethod()
}
}
extension Protocol where Self: ClassB {
func method() {
commonMethod()
}
}
private func commonMethod() {
// do here your stuff
}
Or creating a common protocol, assuming that ClassA and ClassB conform to this one.
protocol CommonProtocol {}
class ClassA: Protocol, CommonProtocol {}
class ClassB: Protocol, CommonProtocol {}
extension Protocol where Self: CommonProtocol {
func method() {
// your stuff
}
}
Related
I'm trying to achieve type constraint on protocols. In my current project I have a following base controller. I examined this answer too but I don't understand why it isn't working.
class BaseViewController: UIViewController {
}
I declared two protocol based on my requirements.
protocol A: AnyObject {
func execute()
}
extension A {
func execute() {
print("Execute")
}
}
protocol B {
func confirm()
}
extension B where Self: BaseViewController & A {
func confirm() {
}
}
What I'm trying to achieve is to prevent all classes which doesn't conform protocol A and BaseViewController also can't conform protocol B also.
However, when I try to conform protocol B in another UIViewController which doesn't conform protocol A there is no error.
class AnotherVC: UIViewController {
}
extension AnotherVC: B {
func confirm() {
}
}
How can I restrict other view controllers to conform protocol B if they don't conform protocol A and inherit from BaseViewController
I am not sure if below code is what you need, do let me know if that’s what you were looking for, else I will be happy to remove my answer.
protocol A:BaseViewController {
func execute()
}
protocol B:A {
func confirm()
}
class BaseViewController: UIViewController {
}
class AnotherVC: B {
}
In above code compiler will give error saying-:
'A' requires that 'AnotherVC' inherit from ‘BaseViewController'
Once you inherit AnotherVC from BaseViewController, it will give another error saying-:
Type 'AnotherVC' does not conform to protocol ‘A'
Once you confirm the implementations errors will be resolved-:
class AnotherVC:BaseViewController, B {
func confirm() {
}
func execute() {
}
}
Both a struct and a class conforms to a protocol. I use 2 protocol extensions with where conditions to add an implementation of the var property for both class and struct.
I'm quite surprised to see a compile error for classes only.
Why does this happen for classes and not for structs?
protocol MyProtocol {
var property:String { get }
}
extension MyProtocol where Self == MyStruct {
var property: String { return "" }
}
extension MyProtocol where Self == MyClass {
var property: String { return "" }
}
struct MyStruct : MyProtocol {}
class MyClass : MyProtocol {} //Type 'MyClass' does not conform to protocol 'MyProtocol'
It does not compile because your
extension MyProtocol where Self == MyClass
provides a default method only for MyClass itself, but not for possible subclasses. Changing the constraint to
extension MyProtocol where Self: MyClass
makes the code compile. Alternatively prevent the creation of subclasses with
final class MyClass : MyProtocol {}
This is not a problem for MyStruct because struct types cannot be inherited from in Swift.
Classes can inherit from other classes.
So some class X may inherit from MyClass.
But your extension provides implementation of MyProtocol properties of if the class is MyClass and not it's descendant. So any class that inherits from MyClass won't have any properties of MyProtocol implemented. And that is the problem.
If you declare MyClass final your code would be valid:
final class MyClass : MyProtocol {}
If you extend conditional extension to any MyClass descendants your code would be valid:
extension MyProtocol where Self: MyClass {
var property: String { return "" }
}
But right now all those potential subclasses lack implementation for MyProtocol and it is not allowed.
Basically I want to know the difference between this
protocol ViewDelegate: class {
func someFunc()
}
and this
protocol ViewDelegate: NSObjectProtocol {
func someFunc()
}
Is there any difference ??
Only Object or Instance type can conform to both type of protocol, where Structure and Enum can't conform to both the type
But the major difference is:
If one declares a protocol like below means it is inheriting NSObjectProtocol
protocol ViewDelegate: NSObjectProtocol {
func someFunc()
}
if the conforming class is not a child class of NSObject then that class need to have the NSObjectProtocol methods implementation inside it. (Generally, NSObject does conform to NSObjectProtocol)
ex:
class Test1: NSObject, ViewDelegate {
func someFunc() {
}
//no need to have NSObjectProtocol methods here as Test1 is a child class of NSObject
}
class Test2: ViewDelegate {
func someFunc() {
}
//Have to implement NSObjectProtocol methods here
}
If one declare like below, it means only object type can conform to it by implementing its methods. nothing extra.
protocol ViewDelegate: class {
func someFunc()
}
when confirming with class it means we only making in object type. So we can declare it as weak or strong
But when confirming with NSObjectProtocol, we make it object type and also we can implement NSObjectProtocol method. which is already define in NSObjectProtocol delegate.
So its up to you which way you want confirm your delegate
I have this protocol:
protocol TestProtocol {
func doSomething
}
I would like to use this protocol to ensure some properties are conforming to it like:
class MyClass {
var detailVC : UIViewController <TestProtocol>
}
like good old ObjC to ensure the detailVC conforms to TestProtocol
protocol MyViewControllerProtocol {
func protoFunc()
}
class MyClass {
var prop: MyViewControllerProtocol?
}
It's as simple as that. But if you want a pre-defined class to conform to a protocol, you then need to make an extension (but then this applies to the class as a whole) or you subclass it.
So...
As an extension to the class as a whole:
extension UIViewController: MyProtocol {
func protoFunc() {
print("do whatever")
}
}
In this case, when extended, you can just set the property as:
var myProperty: UIViewController?
As after being extended, it'll conform as required.
Or just subclass it with:
class MyConformingViewController: UIViewController, MyProtocol {
override func protoFunc() {
print("do whatever")
}
}
In this case, you just set the property as:
var myProp: MyConformingViewController?
And that'll automatically confirm to MyProtocol due to the class being set to conform to it.
You can't force a predesignated class to conform to a protocol which wasn't already designated to conform to it in the first place.
e.g. UIViewController wasn't originally set to confirm to MyOtherProtocol for example
That would defeat the object of protocols in the first place. This is why you either extend it to conform, or subclass it to conform.
So you can implement the method like following:
class detailVC : UIViewController, TestProtocol {
func doSomething() {}
}
In Swift you can't have a variable of one type and also declared as a protocol type.
What you can have is a variable that needs conform more than one protocol.
class MyClass {
var detailVC : TestProtocol
}
class MyClass {
var detailVC : protocol<TestProtocol,SecondProtocol>
}
I am not sure, it looks to me that it is some kind of bug or bad implementation with protocol extensions in Swift 2.0.
I have protocolA, protocolB extending protocolA and implementing methods in protocolB extension.
I have conformed an class instance to conform to protocolB, however when inspected by respondsToSelector for protocolA/B methods the results is false.
import Cocoa
import XCPlayground
protocol ProtocolA : NSObjectProtocol {
func functionA()
}
protocol ProtocolB : ProtocolA {
func functionB()
}
extension ProtocolB {
func functionA() {
print("Passed functionA")
}
func functionB() {
print("Passed functionB")
}
}
class TestClass : NSObject, ProtocolB {
override init () {
}
}
var instance:TestClass = TestClass()
instance.functionA() // Calls code OK..
if instance.respondsToSelector("functionA") {
print("Responds to functionA") // **False, never passing here**
}
if instance.respondsToSelector("functionB") {
print("Responds to functionB") // **False, never passing here**
}
Should be reported as a bug?
Interesting. Looks like a bug to me. It does recognize functions on a class, but not on extension. No matter what type Instance has. Moreover without an extension code would not be compilable, since protocol methods are non optional. So really looks like a bug/feature? in responds to selector implementation.