I have a class
class Presenter<T: UIViewController where T: protocol<ViewInput, ViewController>>: NSObject
{
override init()
{
super.init()
Layer.sharedInstance.service.addListener(self)
}
}
I want Presenter conform to one more Protocol and write an extension:
extension Presenter: OneMoreProtocol
{
func doSomething()
{
self.update()
}
}
But this trow an error: While emitting IR for source file ..../Presenter.swift (Segmentation fault)
The protocol looks:
#objc protocol OneMoreProtocol: AnyObject
{
optional func doSomething()
}
So if I remove extension the error: addListener that is described above in this case throws this error:
Argument type 'Presenter' does not conform to expected type 'OneMoreProtocol'
How can I make conforming in a right way?
Now I think I understand better the issue. The new protocol you added is marked with #objc attribute. You then have to mark the method in the extension Presenter with the #objc like this:
#objc func doSomething()
But you have a bigger problem now: "#objc is not supported within extensions of generic classes."
I am not sure what you are trying to achieve in the end but a simple trick would be a protocol extension.
protocol OneMoreProtocol
{
func doSomething()
}
extension OneMoreProtocol {
func doSomething() {}
}
And now you have an empty implementation for doSomething so you don't have to write an implementation everywhere where the protocol is adopted.
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() {
}
}
I have setup a protocol to send some information back to the previous VC.
I define it like this:
protocol FilterViewControllerDelegate: class {
func didSearch(Parameters:[String: String]?)
}
But what is the difference when using:
protocol FilterViewControllerDelegate {
func didSearch(Parameters:[String: String]?)
}
And when should I use a : class protocol?
Swift 4 version
AnyObject added to a protocol definition like this
protocol FilterViewControllerDelegate: AnyObject {
func didSearch(parameters:[String: String]?)
}
means that only a class will be able to conform to that protocol.
So given this
protocol FilterViewControllerDelegate: AnyObject {
func didSearch(parameters:[String: String]?)
}
You will be able to write this
class Foo: FilterViewControllerDelegate {
func didSearch(parameters:[String: String]?) { }
}
but NOT this
struct Foo: FilterViewControllerDelegate {
func didSearch(parameters:[String: String]?) { }
}
Swift 3 version
:class added to a protocol definition like this
protocol FilterViewControllerDelegate: class {
func didSearch(Parameters:[String: String]?)
}
means that only a class will be able to conform to that protocol.
So given this
protocol FilterViewControllerDelegate: class {
func didSearch(Parameters:[String: String]?)
}
You will be able to write this
class Foo: FilterViewControllerDelegate {
func didSearch(Parameters:[String: String]?) { }
}
but NOT this
struct Foo: FilterViewControllerDelegate {
func didSearch(Parameters:[String: String]?) { }
}
There's also another thing about marking protocols with the class/AnyObject keyword.
Given a protocol like this:
Swift 4 and above (according to docs):
protocol FilterViewControllerDelegate: AnyObject {
func didSearch(with parameters: [String: String]?)
}
Pre-Swift 4 syntax:
protocol FilterViewControllerDelegate: class {
func didSearch(with parameters: [String: String]?)
}
For example, let's assume that you're creating a DetailViewController with delegate property of FilterViewControllerDelegate type:
class DetailViewController: UIViewController {
weak var delegate: FilterViewControllerDelegate
}
If you didn't mark that protocol with class keyword, you wouldn't be able to mark that delegate property as a weak one.
Why?
It's simple - only class based properties can have weak relationships.
If you're trying to avoid a reference cycle, that's the way to go 😁
Swift 5.1, Xcode 11 syntax:
protocol FilterViewControllerDelegate: AnyObject {
func didSearch(Parameters:[String: String]?)
}
this protocol can be adopted by only classes.
To answer your first question -
But what is the difference when using:
the difference from this:
protocol FilterViewControllerDelegate {
func didSearch(Parameters:[String: String]?)
}
is that this protocol can adopt value types, such enums and structs as well.
To answer your second question -
And when should I use a : class protocal?
when you should use class protocol I would like to describe next example from delegate pattern:
Imagine that you have delegate protocol.
protocol PopupDelegate: AnyObject {
func popupValueSelected(value: String)
}
and in another class you want to create a property
var delegate: PopupDelegate?
But this has strong reference that could bring you to problems with memory leaks. One way to fix memory leak is to make delegate property - weak. Until we will not make our protocol only available to apply for classes, Swift thinks we could apply our protocol also to value types.
weak var delegate: PopupDelegate?
If you try to declare your delegate like weak you will see next error:
'weak' var only be applied to class and class-bound protocol types,
not 'PopupDelegate'
But we cant apply weak to value types. So we need to restrict our protocol to a reference type, so swift knows that its a reference type.
To make you available to declare this delegate as weak you need to restrict your protocol to be used by classes only:
protocol PopupDelegate: AnyObject {
func popupValueSelected(value: String)
}
It means that the protocol you define can be adopted only by classes, not structures or enums.
From Official Swift book:
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
// class-only protocol definition goes here }
In the example above, SomeClassOnlyProtocol can only be adopted by class types. It is
a compile-time error to write a structure or enumeration definition
that tries to adopt SomeClassOnlyProtocol.
Swift 3.2 Update:
To declare class only protocol now write:
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
// class-only protocol definition goes here
}
instead of
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
// class-only protocol definition goes here
}
The second snippet still seems to work for now.
Reference: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html
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'm trying to perform a protocol extension method in the background:
performSelectorInBackground(#selector(retrieveCategories()), withObject: nil)
However I get the below error message:
Argument of `#selector` does not refer to an initializer or method
Here is my protocol declaration:
#objc protocol DataRetrievalOperations {
optional func retrieveCategories()
...
}
And my extension:
extension DataRetrievalOperations {
func retrieveCategories() {
...
}
}
How can I achieve this?
Try this:
#selector(DataRetrievalOperations.retrieveCategories)
With omitting class (or protocol) name in #selector(...) notation, Swift assumes the enclosing class, which may be a ViewController, I guess.
One more issue:
It seems Swift cannot implement #objc protocol methods with default implementation in protocol extension.
(I think I have heard something about this, but I couldn't find any articles for now.)
You may need to implement it in your own class's extension or find another way.
extension CategoriesViewController {
func retrieveCategories() {
//...
}
}
I need to add that this will solve the first issue and #selector(retrieveCategories) will work.
You can't add an #Objc method in a Protocol Extension. You need to extend the Class which inherits NSObject and that Protocol and add the objc function there like so:
#objc protocol DataRetrievalOperations {
optional func retrieveCategories()
}
class aClass: NSObject, DataRetrievalOperations {
func method() {
performSelectorInBackground(#selector(retrieveCategories), withObject: nil)
}
}
extension aClass {
#objc func retrieveCategories(){
}
}
This will work.
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.