Trailing where clause for extension of non-generic type
Asked Answered
D

2

42

I have the following code:

func registerNotification(name:String, selector:Selector)
{
    NSNotificationCenter.defaultCenter().addObserver(self, selector: selector, name: name, object: nil)
}

func registerKeyboardNotifications()
{
    let isInPopover = navigationController?.popoverPresentationController != nil
    let ignore = isInPopover && DEVICE_IS_IPAD
    if !ignore {
        registerNotification(UIKeyboardWillShowNotification, selector: Selector("keyboardWillShow:"))
        registerNotification(UIKeyboardWillHideNotification, selector: Selector("keyboardWillHide:"))
    }
}

in an extension to UIViewController. This code is reused by many viewcontroller to register for keyboard notifications. However with Swift 2.2 it produces a warning. I like the new #selector syntax but not sure how to implement it in this case.

I think the correct solution is to make a protocol and extend UIViewController only for instances that conform to that protocol. My code so far:

@objc protocol KeyboardNotificationDelegate
{
    func keyboardWillShow(notification: NSNotification)
    func keyboardWillHide(notification: NSNotification)
}

extension UIViewController where Self: KeyboardNotificationDelegate
{
    func registerKeyboardNotifications()
    {
        let isInPopover = navigationController?.popoverPresentationController != nil
        let ignore = isInPopover && DEVICE_IS_IPAD
        if !ignore {
            registerNotification(UIKeyboardWillShowNotification, selector: #selector(KeyboardNotificationDelegate.keyboardWillShow(_:)))
            registerNotification(UIKeyboardWillHideNotification, selector: #selector(KeyboardNotificationDelegate.keyboardWillHide(_:)))
        }
    }
}

However this get me the error

trailing where clause for extension of non-generic type

on the extension row. Any ideas?

Ducharme answered 23/3, 2016 at 8:52 Comment(0)
D
80

The solution was simple to switch the order in the extension clause:

extension UIViewController where Self: KeyboardNotificationDelegate

should be

extension KeyboardNotificationDelegate where Self: UIViewController
Ducharme answered 23/3, 2016 at 9:3 Comment(2)
This hugely helped me. I was doing the other way around, extension UIViewController where Self: UICollectionViewDelegate but I didn't realize it needed to be flipped with the delegate on the left.Spermophyte
Thanks for asking this question! That helps!Apply
M
23

extension Foo where ... can only be used if Foo is

  1. a generic class or structure: extend with a default implementation for generics conforming to some type constraint,
  2. a protocol containing some associated types, extend with a default implementation for when an associated type conform to some type constraint
  3. a protocol where we extend with a default implementation for when Self is of a specific (object/reference) type, or conforms to some type constraint.

E.g.

// 1
class Foo<T> { }
extension Foo where T: IntegerType {}

struct Foz<T> {}
extension Foz where T: IntegerType {}

// 2
protocol Bar {
    associatedtype T
}
extension Bar where T: IntegerType {}

// 3
protocol Baz {}
extension Baz where Self: IntegerType {}

class Bax<T>: Baz {}
extension Baz where Self: Bax<Int> {
    func foo() { print("foo") }
}

let a = Bax<Int>()
a.foo() // foo

In your case, UIViewController is a non-generic class type, which does not conform to any of the two above.


As you've written in your own answer, the solution is to extend your delegate protocol with a default implementation for cases where Self: UIViewController, rather than attempting to extend UIViewController.

Marelda answered 23/3, 2016 at 9:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.