Подтвердить что ты не робот

Трейлинг, где предложение для расширения не общего типа

У меня есть следующий код:

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:"))
    }
}

в расширении до UIViewController. Этот код повторно используется многими диспетчерами просмотра для регистрации уведомлений о клавиатуре. Однако с Swift 2.2 он выдает предупреждение. Мне нравится новый синтаксис #selector, но не уверен, как его реализовать в этом случае.

Я думаю, что правильным решением является создание протокола и расширение UIViewController только для экземпляров, соответствующих этому протоколу. Мой код:

@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(_:)))
        }
    }
}

Однако это вызовет ошибку

trailing where clause for extension of non-generic type

в строке расширения. Любые идеи?

4b9b3361

Ответ 1

Решение было просто переключить порядок в предложении расширения:

extension UIViewController where Self: KeyboardNotificationDelegate

должен быть

extension KeyboardNotificationDelegate where Self: UIViewController

Ответ 2

extension Foo where ... может использоваться, только если Foo

  • общий класс или структура: расширение с реализацией по умолчанию для дженериков, соответствующих некоторому ограничению типа,
  • протокол, содержащий некоторые связанные типы, расширяется с реализацией по умолчанию, когда ассоциированный тип соответствует некоторому ограничению типа
  • протокол, в котором мы расширяем реализацию по умолчанию, когда Self имеет конкретный тип (объект/ссылка) или соответствует некоторому ограничению типа.

например.

// 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

В вашем случае UIViewController - это не общий тип класса, который не соответствует ни одному из приведенных выше.


Как вы писали в своем собственном ответе, решение состоит в том, чтобы расширить ваш протокол делегатов с реализацией по умолчанию для случаев, когда Self: UIViewController, а не пытаться расширить UIViewController.