Быстрый протокол, свойство IBOutlet не может иметь не-объектный тип
Я хотел бы подключить пользовательский быстрый делегат в IB. Делегат - это объект, который реализует определенный протокол в swift.
protocol ThumbnailTableViewCellDelegate {
func cellWasTouched(thumbnail: Bool, cell: UITableViewCell)
}
class ThumbnailTableViewCell: UITableViewCell {
@IBOutlet var thumbnailTableViewCellDelegate: ThumbnailTableViewCellDelegate?
}
к сожалению, компилятор жалуется на:
error: 'IBOutlet' property cannot have non-object type 'ThumbnailTableViewCellDelegate'
@IBOutlet var thumbnailTableViewCellDelegate: ThumbnailTableViewCellDelegate?
^~~~~~~~~
7 ответов
Вы должны объявить свой ThumbnailTableViewCellDelegate
протокол как @objc
:
@objc protocol ThumbnailTableViewCellDelegate {
func cellWasTouched(thumbnail: Bool, cell: UITableViewCell)
}
Это потому что @IBOutlet
объявляет переменную как weak
, который работает только с объектами. Я не уверен, почему вы не можете просто сказать, что протокол соответствует AnyObject
возможно это ошибка Swift.
Вы можете подключить свои собственные протоколы в IB с этим обходным путем. Это известная проблема с Xcode, поэтому, вероятно, будет решена однажды. До тех пор:
- Объявите делегата как AnyObject - @IBOutlet var делегат:AnyObject!
- Подключите делегата в Интерфейсном Разработчике
- Измените тип розетки на ваш протокол, например, @IBOutlet var делегат:MyDelegate
Это работает для меня.
Не идеально, но есть вариант сделать что-то вроде этого:
@IBOutlet var objectType: NSObject!
private var conformingObject: SomeProtocol {
return objectType as SomeProtocol
}
Должен убедиться, что ваш objectType
соответствует SomeProtocol
или вещи взорвутся
Переменная типа протокола может не быть объектом, потому что структуры и перечисления также могут соответствовать протоколам. Чтобы протокол мог соответствовать только классам, вы можете объявить протокол с помощью @class_protocol
,
На 2023 год...
Вы просто должны добавить@objc
перед определением протокола.
Вам не нужно вносить НИКАКИХ изменений в контроллеры представления.
Пример:
@objc protocol VideoControls {
var playButton: UIButton! { get }
var pauseButton: UIButton! { get }
var timeText: UILabel! { get }
а затем в контроллере представления...
class CompactPlayer: UIViewController, VideoControls {
@IBOutlet var playButton: UIButton!
@IBOutlet var pauseButton: UIButton!
@IBOutlet var timeText: UILabel!
и
class FullScreenPlayer: UIViewController, VideoControls {
@IBOutlet var playButton: UIButton!
@IBOutlet var pauseButton: UIButton!
@IBOutlet var timeText: UILabel!
Вот и все.
В некотором смысле имеет смысл, что IB требует AnyObject, а не ваш конкретный протокол. Объект, к которому вы хотите подключиться, возможно, но не обязательно соответствует протоколу, и протокол может иметь дополнительные параметры - так:
Сделайте ваш протокол так:
@objc public protocol HexViewDataSource: NSObjectProtocol {
@objc optional func dataAtOffset (_ hexView: HexView, offset: UInt64, length: Int)-> Data?
@objc optional func dataLength (_ hexView: HexView) -> UInt64
}
Объявите это в своем классе, например, так:
@IBOutlet weak open var dataSource: AnyObject?
И когда вы начнете использовать его, убедитесь, что он соответствует протоколу и существуют дополнительные опции - вот так:
if let dataSource = dataSource as? HexViewDataSource, let dfr = dataSource.dataAtOffset {
setRowData(offset: offset, data: dfr (self, offset, bytesPerRow))
}
IBOutlets должны указывать указатель на объект, сохраненный в файле пера (или раскадровки). Протокол не является объектом, поэтому вы не можете иметь его в файле пера. Сделайте тип IBOutlet var типом реального объекта, который у вас есть в наконечнике.