Interface Builder, @IBOutlet and protocols for delegate and dataSource in Swift

流过昼夜 提交于 2019-11-28 06:48:38

From the Xcode release notes:

Interface Builder does not support connecting to an outlet in a Swift file when the outlet’s type is a protocol.

Workaround: Declare the outlet's type as AnyObject or NSObject, connect objects to the outlet using Interface Builder, then change the outlet's type back to the protocol.

EDIT: Xcode 9 beta 3 release notes say that this workaround should no longer be necessary.

Adam Waite provides a nice workaround. I however prefer the following solution as it emphasizes the workaround and the extra property can also easily be removed once Xcode gets fixed.

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 {
    ...
}

Hey, is this bug already one and a half years old?

An elegant workaround:

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

See: https://github.com/WenchaoD/FSPagerView/blob/master/Sources/FSPagerView.swift#L88

Another that's not pretty but:

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

This is an old thread, but I thought I'd point out that as of Xcode 9 beta 3, it is now possible to connect a custom delegate written in swift to interface builder.

According to the release notes

Interface Builder now recognizes outlets, actions, and inspectable properties declared on classes which have a Swift protocol extension. (22201035)

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

For me, the reason was the table view was nil at the point I attempted to set it's datasource and delegate. This was due to the designated initializer calling initWithNibName:bundle: which does not guarantee initialized connections. Deferring my delegate and datasource setting to viewDidload worked like a charm.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!