what is 'where self' in protocol extension

32,700

Solution 1

That syntax is: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID521

Consider:

protocol Meh {
    func doSomething()
}

// Extend protocol Meh, where `Self` is of type `UIViewController`
// func blah() will only exist for classes that inherit `UIViewController`. 
// In fact, this entire extension only exists for `UIViewController` subclasses.

extension Meh where Self: UIViewController {
    func blah() {
        print("Blah")
    }

    func foo() {
        print("Foo")
    }
}

class Foo : UIViewController, Meh { //This compiles and since Foo is a `UIViewController` subclass, it has access to all of `Meh` extension functions and `Meh` itself. IE: `doSomething, blah, foo`.
    func doSomething() {
        print("Do Something")
    }
}

class Obj : NSObject, Meh { //While this compiles, it won't have access to any of `Meh` extension functions. It only has access to `Meh.doSomething()`.
    func doSomething() {
        print("Do Something")
    }
}

The below will give a compiler error because Obj doesn't have access to Meh extension functions.

let i = Obj()
i.blah()

But the below will work.

let j = Foo()
j.blah()

In other words, Meh.blah() is only available to classes that are of type UIViewController.

Solution 2

Here is an example which explains that what is the use of where self: UIViewController

protocol SBIdentifiable {
    static var sbIdentifier: String { get }
}

extension SBIdentifiable where Self: UIViewController {
    static var sbIdentifier: String {
        return String(describing: self)
    }
}

extension UIVieWcontroller: SBIdentifiable { }

class ViewController: UIViewController {
  func loadView() {
  /*Below line we are using the sbIdentifier which will return the 
   ViewController class name.
    and same name we would mentioned inside ViewController 
    storyboard ID. So that we do not need to write the identifier everytime. 
   So here where Self: UIViewController means it will only conform the protocol of type UIViewController*/ 

  let viewController = self.instantiateViewController(withIdentifier: 
    self.sbIdentifier) as? SomeBiewController
  }
}

Solution 3

You can find the same example here: WWDC2015-408, (Highly recommend to watch it,it illustrates the reason)

And also, another similar example is Extensions with a Generic Where Clause

struct Stack<Element> {
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
}

The where clause add a requirement to the extension, so that the extension adds the isTop(_:) method only when the items in the stack are equatable.

extension Stack where Element: Equatable {
    func isTop(_ item: Element) -> Bool {
        guard let topItem = items.last else {
            return false
        }
        return topItem == item
    }
}
Share:
32,700
Mini2008
Author by

Mini2008

Updated on March 13, 2020

Comments

  • Mini2008
    Mini2008 over 4 years

    I saw so many examples with below format

    extension Protocolname where Self: UIViewController
    

    What is where Self in protocol extension. I couldn't find the documentation on this.

  • Felix
    Felix about 6 years
    Why people use the same name of Meh for protocol Meh and extension Meh where Self: UIViewController, it seems confusing to me.
  • Brandon
    Brandon about 6 years
    @Felix; Because the extension is actually an extension on that protocol and not on a class itself.. but only when a UIViewController implements it.
  • Oscar
    Oscar about 5 years
    What if I want to write a generic Meh() and a Meh() that will only be executed with it is a ViewController object?