Интерфейсный Разработчик, @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
работал как шарм.