接口生成器、@IBOutlet 以及 Swift 中委托和数据源的协议

Posted

技术标签:

【中文标题】接口生成器、@IBOutlet 以及 Swift 中委托和数据源的协议【英文标题】:Interface Builder, @IBOutlet and protocols for delegate and dataSource in Swift 【发布时间】:2014-10-03 13:52:31 【问题描述】:

无法在 Interface Builder 中将声明为 @IBOutlet 的 CustomView 的委托属性连接到 ViewController - 根本无法建立连接。

这是代码

class CustomView: UIView 
     @IBOutlet var delegate: CustomViewDelegate?


@objc protocol CustomViewDelegate 
     ...



class ViewController: UIViewController, CustomViewDelegate 
     ...

@objc被使用是因为swift protocol, IBOutlet property cannot have non-object type,不知道为什么protocol CustomViewDelegate: class 不起作用。

其他人遇到过类似的事情吗?

【问题讨论】:

Interface Builder 中的UIViewController 的类是否专门设置为ViewController?此外,通常要求(我上次检查)@IBOutlet 属性被定义为隐式展开类型,如下所示:CustomViewDelegate!。这允许它们在实例化时为nil,同时允许您在连接它们之后使用它们而无需可选绑定。 【参考方案1】:

来自 Xcode 发行说明:

当出口的类型是协议时,接口生成器不支持连接到 Swift 文件中的出口。

解决方法:将 outlet 的类型声明为 AnyObject 或 NSObject,使用 Interface Builder 将对象连接到 outlet,然后将 outlet 的类型改回协议。

编辑: Xcode 9 beta 3 发行说明说这种变通方法不再是必要的。

【讨论】:

哇!这工作,谢谢。苹果……请大家齐心协力! 不。改回协议类型后出现“类不符合键值”。 这只是部分地为我工作。在一种情况下,我在 UIView 上定义了自己的委托以连接到 UIViewController,它起作用了。在另一个中,我在 UIViewController 上定义我的委托以连接到另一个 UIViewController,但它没有。我尝试了很多配置。有什么想法@matt 这里可能会发生什么? “在另一个地方,我在 UIViewController 上定义我的委托以连接到另一个 UIViewController,但它没有”这对我来说毫无意义,@josephap。您可以从不在情节提要中从一个视图控制器到另一个视图控制器绘制任何类型的出口连接,所以我无法想象您在第一名。这与 Swift 完全无关。这只是关于笔尖如何工作的事实。 - 看我的书:apeth.com/iosBook/ch07.html#SECconnectionBetweenNibs 是的,马特,我现在明白了。我没有太多使用 Storyboard,只是发现您只能在视图控制器内连接插座,而不是在它们之间。我确实有一个与 Swift 相关的问题,您的回答对此有所帮助。谢谢。【参考方案2】:

Adam Waite provides a nice workaround. 然而,我更喜欢以下解决方案,因为它强调了解决方法,并且一旦 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 
    ...

嘿,这个bug已经一岁半了吗?

【讨论】:

【参考方案3】:

一个优雅的解决方法:

#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#L88

【讨论】:

【参考方案4】:

另一个不漂亮但是:

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

【讨论】:

好答案!使用这种方式来防止更改类型通常是 Outlet。【参考方案5】:

这是一个旧线程,但我想我要指出的是,从 Xcode 9 beta 3 开始,现在可以将用 swift 编写的自定义委托连接到界面生成器。

根据发行说明

界面生成器现在可以识别出口、动作和可检查 在具有 Swift 协议扩展的类上声明的属性。 (22201035)

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

【讨论】:

【参考方案6】:

对我来说,原因是表视图是nil,当时我试图设置它的数据源和委托。这是由于指定的初始化程序调用initWithNibName:bundle: 不能保证initialized connections。将我的委托和数据源设置推迟到 viewDidload 就像一个魅力。

【讨论】:

以上是关于接口生成器、@IBOutlet 以及 Swift 中委托和数据源的协议的主要内容,如果未能解决你的问题,请参考以下文章

ScrollView中的IBOutlet生成为零

Swift、iboutlet 和自定义控件

如何使用 Swift 以编程方式分配 IBOutlet?

swift 协议,IBOutlet 属性不能有非对象类型

无法在 Swift 2 中将 TableView @IBOutlet 连接到 ViewController

Swift 4:@IBOutlet UITextView 崩溃