Default protocol implementation causes 'does not conform to protocol' error - ios

I am trying to add a default implementation to one of my delegate methods. However, after adding the default implementation and removing the method from the class that implements the protocol, I get does not conform to protocol error. It works in a playground.
protocol NavigationDelegate: NSObjectProtocol {
func didSetToolbarVisible(_ isVisible: Bool)
}
extension NavigationDelegate {
func didSetToolbarVisible(_ isVisible: Bool) {
print("Default implementation")
}
}
class MyViewController: NavigationDelegate {
// 'does not conform to protocol' error
}
What am I missing?

A class does not conform to NSObjectProtocol by default, that causes the error.
Change
protocol NavigationDelegate: NSObjectProtocol
to
protocol NavigationDelegate: class

Your NavigationDelegate uses a base protocol of NSObjectProtocol. This means that anything that conforms to NavigationDelegate must also conform to NSObjectProtocol. Change your class declaration to the following:
class MyViewController: NSObject, NavigationDelegate.

Solved it! My NavigationDelegate and its extension were in a different target than the one that MyViewController belongs to. Simply moving the extension to the same target worked.
Hope this helps someone in the future 🤞

Related

Why does swift hide default implementation for restricted protocols?

I have a protocol which declaration looks like this:
protocol RefreshableView where Self: UIView {
func reload()
}
And it has default implementation which looks as follows:
extension RefreshableView {
func reload() {
print("Default implementation")
}
}
Then if I declare another (empty) extension of UIView conforming to this protocol I get compile-time error stating that UIView does not conform to the protocol.
extension UIView: RefreshableView {}
It should not be a case from my point of view, as default implementation is provided. However if I remove where statement (restriction to the classes which can conform to the protocol) from declaration of the protocol, everything works as expected. Another option to silence this error is to give the same where statement next to default extension declaration, but it feels redundant as I already let compiler know the protocol is supposed for narrow audience. Is there an explanation to this behavior?
What you're saying is that this doesn't compile:
protocol RefreshableView where Self: UIView {
func reload()
}
extension RefreshableView {
func reload() {
print("Default implementation")
}
}
extension UIView: RefreshableView {
}
As Rob Napier points out in a comment, that's a very odd thing to say, because if UIView itself is going to adopt RefreshableView, then what's the protocol for? The original declaration of the protocol means that only a UIView subclass can adopt RefreshableView, so what the compiler expects is that that's what will happen:
protocol RefreshableView where Self: UIView {
func reload()
}
extension RefreshableView {
func reload() {
print("Default implementation")
}
}
class MyView: UIView {}
extension MyView: RefreshableView {
}
That is a useful real-world case, and it compiles just fine.
So you could file a bug against your original code, but you have to admit it
is a very peculiar edge case to start with; you are saying something that no one would in fact ever say.

View Controller only Protocol has no access to View Controller properties

I have a UIViewController only protocol
protocol VCProtocol where Self: UIViewController {}
I have a function with VCProtocol parameter. Inside the function I can not access any property of UIViewController
func testFunction(vcProtocol: VCProtocol) {
// vcProtocol.view ‼️ error: Value of type 'VCProtocol' has no member 'view'
}
Though I can cast the protocol parameter to UIViewController and then access the property like this:
func testFunction(vcProtocol: VCProtocol) {
(vcProtocol as! UIViewController).view
}
Is this is the way? Do we have any better way?
You can use the & operator to combine protocols
protocol VCProtocol where Self: UIViewController {}
func testFunction(vcProtocol: VCProtocol & UIViewController) {
let view = vcProtocol.view
}
It seems like this is now supported properly from Swift 5. You can try it Xcode 10.2 beta 4. For older versions, you would have to resort to #Ricky Mo's solution.
protocol VCProtocol: UIViewController {
func testFunction(vcProtocol: VCProtocol)
}
class A: UIViewController, VCProtocol {
func testFunction(vcProtocol: VCProtocol) {
debugPrint(vcProtocol.view)
}
}
From the 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)

How do you create a base class with a weak delegate that conforms to a generic protocol?

I want to create a base class for UIViews that require that a delegate conform to a specific protocol defined by the View.
class BaseView<P>: UIView {
weak var delegate: P?
}
protocol MyProtocol {}
class MyView: BaseView<MyProtocol> {}
This gives me the error: "'weak' must not be applied to non-class-bound 'T'; consider adding a protocol conformance that has a class bound".
How do I fix this error? Or is there some work around? Or is it not so necessary to make the delegate variable weak in the first place? Thanks in advance.
Since weak is a property assigned to anything that is of class type and not struct, you have to explicitly constraint your generic parameter to be of class type and you do that this way:
class BaseView<P: AnyObject>: UIView {
weak var delegate: P?
}
#objc protocol MyProtocol {
}
class MyView: BaseView<MyProtocol> {
}
Only one need of clarification. Usually to make a protocol be of class type usally you would make it conform to class this way:
protocol MyProtocol: class { }
However, for some reason the compiler throws an error if you were to do it that way. I learned that this is a bug that could be learned about more here:
How to require that a protocol can only be adopted by a specific class
So adding the #objc helps silence the warning and error both.
You should add type constraint to your generic by adding MyProtocol and create a class that conforms MyProtocol.
You can find more info here.
Updated code:
class BaseView<P: MyProtocol>: UIView {
weak var delegate: MyProtocol?
}
protocol MyProtocol: class {}
class MyProtocolImp: MyProtocol {
}
class MyView: BaseView<MyProtocolImp> {
}
But I don't know why you use P parameter in class.
You can write without this:
class BaseView: UIView {
weak var delegate: MyProtocol?
}
protocol MyProtocol: class {}
class MyView: BaseView {
}

Swift class doesn't conform to objective c protocol inherited from swift protocol

I am having an issue checking for objective-c protocol conformance when it is inherited from a swift protocol.
As far as I understand the following code should print true.
(Swift 3)
import UIKit
protocol MyProtocol: UITableViewDelegate {}
class MyClass: UIViewController, MyProtocol {}
let myClass = MyClass()
print(myClass.conforms(to: UITableViewDelegate.self))
// prints false
let viewController = myClass as UIViewController
print(viewController as? UITableViewDelegate ?? "not a delegate")
// prints not a delegate
If anyone knows why this is happening or how to properly check this conformance that'd be great
In Swift 3, adding #objc to my MyProtocol works.
Why it's true for me(tested with Swift 3.2 and 4.0), did we really do the same thing:

Swift: How to implement CVCalendar

I am trying to implement the CVCalendar cocoapod (https://github.com/Mozharovsky/CVCalendar) and in the instructions it says:
'CVCalendar requires an implementation of two protocols CVCalendarViewDelegate and CVCalendarMenuViewDelegate, please implement both.'
I dont understand how to go about doing this.
You just need to make your class a subclass of CVCalendarViewDelegate and CVCalendarMenuViewDelegate.
class ViewController: UIViewController, CVCalendarViewDelegate, CVCalendarMenuViewDelegate {
Documentation: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-ID195
Take a look at the answer to this question: Conform to protocol in ViewController, in Swift
As per Oliver's answer you need to add protocols to your class declaration :
class ViewController: UIViewController,CVCalendarMenuViewDelegate,CVCalendarViewDelegate {
You also need to add these two functions to comply with the new protocols:
func presentationMode() -> CalendarMode{
return .monthView
}
func firstWeekday() -> Weekday{
return .monday
}

Resources