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