Multiple protocol inheritance in Swift 2.0 using extension protocols [duplicate] - ios

Given the two protocols and their extensions:
protocol FirstDelegate {
func someFunc()
}
protocol SecondDelegate {
func someFunc()
}
extension FirstDelegate {
func someFunc() {
print("First delegate")
}
}
extension SecondDelegate {
func someFunc() {
print("Second delegate")
}
}
and trying to conform to both of them:
class SomeClass: FirstDelegate, SecondDelegate {}
I receive compile-time error:
Type 'SomeClass' does not conform to protocol 'FirstDelegate'
Exchanging FirstDelegate and SecondDelegate:
class SomeClass: SecondDelegate, FirstDelegate {}
produces reverse:
Type 'SomeClass' does not conform to protocol 'SecondDelegate'
Removing one of the extensions resolves the problem. Ditto providing implementation for someFunc() inside SomeClass.
This protocol extension functionality is rather new to me. Also the information about it in an Apple's official 'Swift Programming Guide (Prerelease)' is scarce at the moment.
Did I violate some rules of protocol extensions here?

A protocol defines requirements (methods, properties, ...) for a
conformant type.
protocol FirstDelegate {
func someFunc()
}
protocol SecondDelegate {
func someFunc()
}
defines two protocols with the same required method someFunc().
A conformant type must implement this method:
class SomeClass: FirstDelegate, SecondDelegate {
func someFunc() {
print("SomeClass implementation")
}
}
A protocol extension provides method and property implementations
to conformant types. A special case of a protocol extension is a
default implementation, which is what you defined here:
extension FirstDelegate {
func someFunc() {
print("First delegate")
}
}
It defines a default implementation of someFunc() for all types
conforming to FirstDelegate. Since this is the only required
method of that protocol, a conforming class need not define the
method at all:
class SomeClass: FirstDelegate {
}
SomeClass().someFunc() // Output: First delegate
But if the class provides its own implementation then that
will be used:
class SomeClass: FirstDelegate {
func someFunc() {
print("SomeClass implementation")
}
}
SomeClass().someFunc() // Output: SomeClass implementation
In your case, you have defined default implementations of someFunc()
for both protocols:
extension FirstDelegate {
func someFunc() {
print("First delegate")
}
}
extension SecondDelegate {
func someFunc() {
print("Second delegate")
}
}
A class can still conform to both protocols if it provides its own
implementation of the required method:
class SomeClass: FirstDelegate, SecondDelegate {
func someFunc() {
print("SomeClass implementation")
}
}
But the class cannot conform by using the default implementation
class SomeClass: FirstDelegate, SecondDelegate {
}
for both protocols
because there is a conflict. It is unspecified which default
implementation should be used, and that's why the compiler complains.
Actually the class now conforms to none of the protocols.
This can be seen in the full compiler log in the Report navigator:
main.swift:24:7: error: type 'SomeClass' does not conform to protocol 'FirstDelegate'
class SomeClass: FirstDelegate, SecondDelegate {
^
main.swift:5:10: note: multiple matching functions named 'someFunc()' with type '() -> ()'
func someFunc()
^
main.swift:19:10: note: candidate exactly matches
func someFunc() {
^
main.swift:13:10: note: candidate exactly matches
func someFunc() {
^
main.swift:24:7: error: type 'SomeClass' does not conform to protocol 'SecondDelegate'
class SomeClass: FirstDelegate, SecondDelegate {
^
main.swift:9:10: note: multiple matching functions named 'someFunc()' with type '() -> ()'
func someFunc()
^
main.swift:19:10: note: candidate exactly matches
func someFunc() {
^
main.swift:13:10: note: candidate exactly matches
func someFunc() {
^

Related

Non-'#objc' method does not satisfy requirement of '#objc' protocol [duplicate]

This question already has answers here:
Non-'#objc' method does not satisfy optional requirement of '#objc' protocol
(3 answers)
Closed 1 year ago.
I've put the following into a Playground to try and understand this and I just don't:
import Foundation
#objc protocol Sample {
var value: Int { get set }
func increase()
func decrese()
}
extension Sample {
func increase() {
value += 1
}
func decrease() {
value -= 1
}
}
class Test: Sample {
var value: Int = 0
}
The error appears next to the class declaration for Test saying:
Non-'#objc' method 'increase()' does not satisfy requirement of '#objc' protocol 'Sample'
If I re-declare increase() and decrease() in the class then the warning is silenced. Or also if I remove the declarations from the protocol. Could someone please explain?
EDIT
I do need an Objective-C class to conform to this protocol as well, hence the #objc at the start.
The problem is that you’re defining these methods in a protocol extension. This is used to define a “default implementation” for a protocol (i.e. if a type doesn’t implement the method, the protocol’s implementation will be called).
But Objective-C doesn’t have the concept of default implementations for protocols. So it doesn’t makes sense to declare the protocol as #objc and have default implementations within the Swift protocol extension. An Objective-C class conforming to this protocol would never be able to enjoy these Swift default implementations.
The below code works with empty protocol methods' implementation in the Protocol extension class
import Foundation
protocol Sample {
var value: Int { get set }
func increase()
func decrease()
}
extension Sample {
func increase() { }
func decrease() { }
}
class Test: Sample {
var value: Int = 0
}
or if you want some default implementation of Sample protocol methods in the extension then use
import Foundation
protocol Sample {
var value: Int { get set }
func increase()
mutating func decrease()
}
extension Sample {
func increase() {
print("do anything")
}
mutating func decrease() {
value -= 1
}
}
class Test: Sample {
var value: Int = 0
}
mutating is added before the protocol method decrease() because it modifies the Protocol variable value.
If the Protocol extension doesn't modify any of the Protocol variable (e.g. increase()), then there is no need of mutating keyword

Extend a Protocol with Multiple Constraints for One OR the Other - Swift

I want to extend protocol with a default implementation that satisfies OR ( || ) constraint.
class A { }
class B { }
protocol SomeProtocol { }
/// It will throw error for ||
extension SomeProtocol where Self: A || Self: B {
}
You can't extend a protocol with OR as you can't do it in a if let, because with this the compiler infers the type of self or of the var, so if it conforms 2 types, the compiler doesn't know of what type is self.
(When you type self. or any var. the compiler always knows what type of var is in compiler type, in that case it would be in runtime). So the easiest way is to make that the 2 types conforms a protocol and do a extension of that protocol. So the compiler knows that self conforms a protocol and he doesn't care of the exact type of Self (But you will be able to use only the properties declared in the protocol).
protocol ABType {
// Properties that you want to use in your extension.
}
class A: ABType, SomeProtocol { }
class B: ABType, SomeProtocol { }
protocol SomeProtocol { }
extension SomeProtocol where Self: ABType {
}
Also if you want to apply the extension to both types you have to do it one by one.
extension A: SomeProtocol { }
extension B: SomeProtocol { }
// Silly example:
(In this case is not really useful, but it is just to show how to make to make 2 classes conforms a protocol and to make a extension of it using a method declared in that protocol and creating a default implementation.)
protocol ABType {
func getName()
}
class AClass: ABType {
func getName() {
print ("A Class")
}
}
class BClass: ABType, someProtocol {
func getName() {
print ("B Class")
}
}
protocol someProtocol {
func anotherFunc()
}
extension someProtocol where Self: ABType {
func anotherFunc() {
self.getName()
}
}
let a = AClass()
// a.anotherFunc() <- Error, A cant call anotherFunc
let b = BClass()
b.anotherFunc()

Conformance issues even after fulfilling requirements using protocol extensions for #objc protocols

Let us consider this example which compiles without any issues :
protocol AProtocol {
func veryImportantMethod()
}
protocol BProtocol : AProtocol {
}
extension BProtocol {
func veryImportantMethod() {
print("A's protocol requirement satisfied!")
}
}
class ConcreteClass : BProtocol {
}
However, if we do this :
#objc protocol AProtocol { //Added #objc here
func veryImportantMethod()
}
protocol BProtocol : AProtocol {
}
extension BProtocol {
func veryImportantMethod() {
print("A's protocol requirement satisfied!")
}
}
class ConcreteClass : BProtocol {
}
It doesn't compile with a message saying :
Type 'ConcreteClass' does not conform to protocol 'AProtocol'
However, if we actually implement it,
class ConcreteClass : NSObject, BProtocol {
func veryImportantMethod() { }
}
the code compiles. Why is this happening? Is there anything that I am missing here?
I am trying to achieve this form of protocol hierarchy for UITableViewDataSource and I really do not want to repeat tableView:cellForRowAtIndexPath: code across conformants.
The compiler wants to make sure that the class can be compiled with ObjC. Once you inherit from an ObjC class (like NSObject) the compiler knows it, but you implement the extension before that point. You could avoid the error by defining the protocol to be implemented by a class that inherits from NSObject, like this:
#objc protocol AProtocol {
func veryImportantMethod()
}
protocol BProtocol : AProtocol {
}
class BProtocolClass: NSObject {
}
extension BProtocolClass {
func veryImportantMethod() {
print("A's protocol requirement satisfied!")
}
}
class ConcreteClass: BProtocolClass {
}

Swift 2.2 Generics: "Cannot convert return expression of type ItemPageControllerFactory to return type T"

I have an 'ItemContainer' protocol and UIViewController subclass 'ItemPageController' that conforms to the protocol.
I also have a 'ItemContainerControllerFactory' protocol and a struct that conforms to this protocol.
The issue: I wish to create a method that returns an appropriate ItemControllerControllerFactory sub-type. However, I get the following compiler error: "Cannot convert return expression of type ItemPageControllerFactory to return type T"
protocol ItemContainer {
func navigateToItem(item:Item)
}
class ItemPageController : UIViewController, ItemContainer {
func navigateToItem(item:Item) { ... }
}
protocol ItemContainerControllerFactory {
associatedtype ContainerType : UIViewController, ItemContainer
func itemContainerController() -> ContainerType
}
struct ItemPageControllerFactory: ItemContainerControllerFactory {
typealias ContainerType = ItemPageController
func itemContainerController() -> ContainerType {
return ContainerType()
}
}
//Goal: Be able to return different ItemContainerControllerFactory depending on some logic... (Currently hard coded to ItemPageControllerFactory)
func itemContainerFactory<T:ItemContainerControllerFactory>() -> T {
return ItemPageControllerFactory() //COMPILER ERROR: "Cannot convert return expression of type ItemPageControllerFactory to return type T"
}
Any ideas of what I'm doing wrong?
In order to create a generic instance with protocols as you are, you need an initializer in your protocol
something like this:
protocol TestProtocol {
init()
}
func create<T: TestProtocol>() -> T {
return T()
}

Swift protocol extension method dispatch with superclass and subclass

I found an interesting behaviour which seems like a bug...
Based on the behaviour described the following articles:
https://medium.com/ios-os-x-development/swift-protocol-extension-method-dispatch-6a6bf270ba94
http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future
The output is not what I expect, when I add SomeSuperclass, rather than directly adopting the protocol.
protocol TheProtocol {
func method1()
}
extension TheProtocol {
func method1() {
print("Called method1 from protocol extension")
}
func method2NotInProtocol() {
print("Called method2NotInProtocol from protocol extension")
}
}
// This is the difference - adding a superclass
class SomeSuperclass: TheProtocol {
}
// It works as expected when it simply adopts TheProtocol, but not when it inherits from a class that adopts the protocol
class MyClass: SomeSuperclass {
func method1() {
print("Called method1 from MyClass implementation")
}
func method2NotInProtocol() {
print("Called method2NotInProtocol from MyClass implementation")
}
}
let foo: TheProtocol = MyClass()
foo.method1() // expect "Called method1 from MyClass implementation", got "Called method1 from protocol extension"
foo.method2NotInProtocol() // Called method2NotInProtocol from protocol extension
Do you know if this is a bug, or by design? A colleague suggested perhaps mixing inheritance and protocol extensions might not work as expected. I was intending to use the protocol extension to provide a default implementation... if I can't do it, then I will sadly have to mark it #objc and go back to an optional protocol.
From the post The Ghost of Swift Bugs Future, here are the rules for dispatch for protocol extensions that are mentioned at the end of the post.
IF the inferred type of a variable is the protocol:
AND the method is defined in the original protocol THEN the
runtime type’s implementation is called, irrespective of whether
there is a default implementation in the extension.
AND the method is not defined in the original protocol, THEN the
default implementation is called.
ELSE IF the inferred type of the variable is the type THEN the type’s implementation is called.
So in your condition, you're saying that method1() is defined in the protocol and it has been implemented in the subclass. But your superclass is adopting the protocol but it is not implementing the method1() and subclass just inherits from the Superclass and doesn't adopt to the protocols directly. That's why I believe that is the reason when you call foo.method1(), it doesn't invoke the the subclass implementation as stated by point 1 & 2.
But when you do,
class SomeSuperclass: TheProtocol {
func method1(){
print("super class implementation of method1()")}
}
class MyClass : SomeSuperclass {
override func method1() {
print("Called method1 from MyClass implementation")
}
override func method2NotInProtocol() {
print("Called method2NotInProtocol from MyClass implementation")
}
}
and then when you call,
let foo: TheProtocol = MyClass()
foo.method1() // Called method1 from MyClass implementation
foo.method2NotInProtocol()
So what could be the workaround for this bug (which seems to be a bug) is that, you need to implement the protocol method in the superclass and then you need to override the protocol method in the sub class. HTH
Please check the code below:
import UIKit
protocol TheProtocol {
func method1()
func method2NotInProtocol()
}
extension NSObject {
func method1() {
print("Called method1 from protocol extension")
}
func method2NotInProtocol() {
print("Called method2NotInProtocol from protocol extension")
}
}
// This is the difference - adding a superclass
class SomeSuperclass :NSObject, TheProtocol {
override func method1() {
print("Called method1 from SomeSuperclass implementation")
}
}
// It works as expected when it simply adopts TheProtocol, but not when it inherits from a class that adopts the protocol
class MyClass : SomeSuperclass {
override func method1() {
print("Called method1 from MyClass implementation")
}
override func method2NotInProtocol() {
print("Called method2NotInProtocol from MyClass implementation")
}
}
let foo: TheProtocol = MyClass()
foo.method1() // expect "Called method1 from MyClass implementation", got "Called method1 from protocol extension"
foo.method2NotInProtocol() // Called method2NotInProtocol from protocol extension
Instead of writing extension to TheProtocol, write extension to a abstract class(NSObject in above code). This works as expected.
An option that hasn't been considered is to split up your protocol into several smaller ones, such that the superclass does not need to conform to protocols containing methods it does not intend to implement. The subclass can then subscribe to these other protocols separately.

Resources