Протокол Swift, вложенный в класс

Я хотел бы вложить протокол в свой класс, чтобы реализовать шаблон делегата следующим образом:

class MyViewController : UIViewController {

    protocol Delegate {
        func eventHappened()
    }

    var delegate:MyViewController.Delegate?

    private func myFunc() {
        delegate?.eventHappened()
    }
}

Но компилятор не позволит:

Протокол «Делегат» не может быть вложен в другое объявление

Я могу легко заставить его работать, объявив MyViewControllerDelegate вне области видимости класса.
Мой вопрос: почему такое ограничение?


person Axel Guilmin    schedule 17.03.2016    source источник
comment
Это также обсуждалось на форумах разработчиков Apple: forums.developer.apple.com/thread/15195   -  person Axel Guilmin    schedule 26.11.2018


Ответы (3)


согласно быстрой документации

Swift позволяет вам определять вложенные типы, посредством чего вы вкладываете поддерживающие перечисления, классы и структуры в определение типа, который они поддерживают.

Учитывая протоколы, которых нет в этом списке, похоже, что они в настоящее время не поддерживаются. Возможно, они добавят эту функцию в какой-то момент (в конце концов, Swift был анонсирован менее чем через 2 года). Любая идея о том, почему они не будут или не будут, будет спекуляцией с моей стороны.

person GetSwifty    schedule 17.03.2016

это моя работа вокруг:

protocol MyViewControllerDelegate : class {
    func eventHappened()
}

class MyViewController : UIViewController {
    typealias Delegate = MyViewControllerDelegate
    weak var delegate: Delegate?
    
    private func myFunc() {
        delegate?.eventHappened()
    }
}
person Oscar van der Meer    schedule 09.11.2018
comment
Мне это не кажется обходным путем, скорее, это единственно возможный путь)) - person rommex; 16.06.2019

Отдельная проблема с вашим классом заключается в том, что delegate не имеет конкретного типа. Вы можете сойти с рук, объявив его MyViewController.Delegate?, потому что это необязательный тип и может быть .None. Но это просто делает ваш личный код myFunc мертвым. Только перечисления, классы и структуры могут соответствовать протоколу. Какой из этих трех типов delegate?

Тем не менее, это не причина вашей проблемы. Когда я создаю реальный тип для delegate и заставляю его соответствовать протоколу Delegate, я все равно получаю ту же ошибку.

class MyViewController: UIViewController {

  protocol Delegate {
    func eventHappened()
  }

  class Classy: Delegate {
    func eventHappened() {
      print("eventHappened")
    }
  }

  var delegate: Classy? = Classy()

  func myFunc() {
    delegate?.eventHappened()
  }
}

введите здесь описание изображения

В качестве эзотерического упражнения это может быть интересно для расширения границ того, что может делать класс, но никто не должен каждый раз пытаться объявлять протокол внутри класса. Протоколы связаны с композицией типов и коллекциями. Не существует сценария повторного использования кода, когда вы ограничены тем, что находитесь в одном и том же внешнем классе.

person Price Ringo    schedule 17.03.2016
comment
Протоколы делегата предназначены для реализации пользователями этого класса. То, что вы описываете как проблему, на самом деле не проблема — это важный шаблон проектирования программного обеспечения, используемый во всех платформах Apple Cocoa и CocoaTouch. - person Slipp D. Thompson; 22.02.2017
comment
Вы можете получить полное представление о том, как делегаты предназначены для использования в Cocoa (и, соответственно, в Objective-C и Swift, поскольку первый был разработан в тандеме с Cocoa, а последний в основном для приложений Cocoa) в Руководство по основным компетенциям Cocoa, раздел "Делегирование". - person Slipp D. Thompson; 22.02.2017