Интерфейсный Разработчик, @IBOutlet и протоколы для делегата и источника данных в Swift

Не удается подключить делегировать свойство CustomView объявлен как @IBOutlet дляViewController в Интерфейсном Разработчике - просто не может установить соединение.

Вот код

class CustomView: UIView {
     @IBOutlet var delegate: CustomViewDelegate?
}

@objc protocol CustomViewDelegate {
     ...
}


class ViewController: UIViewController, CustomViewDelegate {
     ...
}

@objc используется из-за протокола swift, свойство IBOutlet не может иметь не-объектный тип, не знаю почему protocol CustomViewDelegate: class {} не работает

Кто-нибудь еще сталкивался с чем-то подобным?

6 ответов

Решение

Из примечаний к выпуску Xcode:

Интерфейсный Разработчик не поддерживает подключение к розетке в файле Swift, когда тип розетки является протоколом.

Обходной путь: Объявите тип розетки как AnyObject или NSObject, подключите объекты к розетке с помощью Interface Builder, затем измените тип розетки обратно на протокол.

РЕДАКТИРОВАТЬ: примечания к выпуску Xcode 9 beta 3 говорят, что этот обходной путь больше не требуется.

Адам Уэйт предлагает хороший обходной путь. Однако я предпочитаю следующее решение, поскольку оно подчеркивает обходной путь, и дополнительное свойство также может быть легко удалено после исправления Xcode.

class CustomView: UIView {
    @IBOutlet
    public var delegate: CustomViewDelegate?

    /// Workaround for Xcode bug that prevents you from connecting the delegate in the storyboard.
    /// Remove this extra property once Xcode gets fixed.
    @IBOutlet
    public var ibDelegate: AnyObject? {
        get { return delegate }
        set { delegate = newValue as? CustomViewDelegate }
    }

    func someMethod() {
        // Here we always refer to `delegate`, not `ibDelegate`
        delegate?.onSomethingHappened()
    }
}

@objc protocol CustomViewDelegate {
    ...
}

Эй, эта ошибка уже полтора года?

Элегантный обходной путь:

#if TARGET_INTERFACE_BUILDER
@IBOutlet open weak var delegate: AnyObject?
#else
open weak var delegate: CustomViewDelegate?
#endif

См.: https://github.com/WenchaoD/FSPagerView/blob/master/Sources/FSPagerView.swift

Другой, который не симпатичен, но:

@IBOutlet weak var ibDelegate: NSObject?
@IBOutlet weak var ibDataSource: NSObject?
var delegate: MultipleButtonViewDelegate? { return ibDelegate as? MultipleButtonViewDelegate }
var dataSource: MultipleButtonViewDataSource? { return ibDataSource as? MultipleButtonViewDataSource }

Это старая ветка, но я подумал, что с Xcode 9 beta 3 теперь можно подключить пользовательский делегат, написанный на swift, к построителю интерфейса.

Согласно примечаниям к выпуску

Интерфейсный Разработчик теперь распознает выходы, действия и проверяемые свойства, объявленные в классах, имеющих расширение протокола Swift. (22201035)

// Can connect this to interface builder now    
class MyViewController: UIViewController {
    @IBOutlet weak var myDelegate: TheNewDelegate?
}

Для меня причина была в том, что табличное представление было nil в тот момент, когда я попытался установить его источник данных и делегировать. Это произошло из-за вызова инициализатора initWithNibName:bundle: который не гарантирует инициализированные соединения. Отложить мой делегат и настройки источника данных в viewDidload работал как шарм.

Другие вопросы по тегам