When to use `protocol` and `protocol: class` in Swift?
Solution 1:
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]?) { }
}
Solution 2:
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 😁
Solution 3:
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)
}
Solution 4:
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.
Solution 5:
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