【问题标题】:Making outlet for the object from a xib file从 xib 文件中为对象制作出口
【发布时间】:2017-06-14 21:31:20
【问题描述】:

我有一个 Hint.xib 文件,其中的元素很少(标签、图像视图和按钮)。我有一个名为 Hint 的类,它是 UIView 的子类,它加载这个 xib。

Hint 类的实现如下所示:

import UIKit

@IBDesignable

extension UIView {
    class func fromNib<T : UIView>() -> T? {
        guard
            let nibs = Bundle(for: self).loadNibNamed(String(describing: self), owner: nil, options: nil),
            let nib = nibs.first
            else {
                return nil
        }

        return nib as? T
    }
}

class Hint:UIView {
    @IBOutlet weak var hintLabel: UILabel! 
    private func setup(){

        if let view = Hint.fromNib(){
            self.addSubview(view)
            view.frame = self.bounds
        }
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        setup()
    }


    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()

        setup()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

       setup()
    }
}

当前设置

目前,在情节提要上,我添加了一个视图控制器,并在该视图控制器的视图中拖动了一个 UIView。之后,我将其自定义类设置为Hint。另外我正在使用@IBDesignable 指令并覆盖prepareForInterfaceBuilder() 以在设计中呈现所有内容,这一切都有效,直到我尝试为作为Hint.xib 文件一部分的标签(hintLabel)创建一个出口.

我收到下一个错误:

由于未捕获的异常“NSUnknownKeyException”而终止应用程序, 原因:'[ setValue:forUndefinedKey:]: 这个 类与键提示标签的键值编码不兼容。'

我选择了我的 Hint.xib 文件 -> 文件的所有者,并检查了 Identity Inspector 中是否一切正常,那里似乎一切正常:

通过 IB 或代码更改此标签文本的适当方法是什么。另外,我不能只在 Hint.xib 中更改这个标签的文本,因为我可能在一个屏幕上有多个视图来加载(从)这个 xib,并且所有这些视图都应该有不同的文本。我想我在这里遗漏了一些明显的东西……感谢您的提示:))

【问题讨论】:

    标签: ios swift xcode interface-builder xib


    【解决方案1】:

    问题是您必须使用“owner:self”从捆绑包中加载 xib,所以它应该如下所示:

    class Hint:UIView {
        @IBOutlet var view: UIView!
        @IBOutlet weak var hintLabel: UILabel!
        private func setup(){
    
            Bundle.main.loadNibNamed("Hint", owner: self, options: nil)
            self.addSubview(view)
            view.frame = self.bounds
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
    
            setup()
        }
    
    
        override func prepareForInterfaceBuilder() {
            super.prepareForInterfaceBuilder()
    
            setup()
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
    
            setup()
        }
    }
    

    另外不要忘记在 xib 文件中将 File Owner 设置为 Hint 类(不是 UIView)

    【讨论】:

    • 它没有用。我得到了同样的错误......另外,我试图在这里实现几件事:1)有一个可重用的xib。 2) 能够在同一个视图控制器上初始化多个视图,以便每个视图都有一个带有不同文本的标签。 3) 在设计时对故事板中的所有视图进行实时预览。
    • 关于你的建议,你能解释一下你为什么这么建议吗?你能说得更准确点吗?
    • 视图是可选的,你应该使用hintLabel = (view as! Hint).hintLabel进行转换
    • @MücahitTekin 好吧,这部分工作 - 在运行时一切正常,但在设计时,情节提要中的实时预览都搞砸了。但我通过使用 ` if let hView = Bundle(for: Hint.self).loadNibNamed("Hint", owner: self, options: nil)?.first {...` 而不是主包来解决这个问题。跨度>
    【解决方案2】:

    你所拥有的非常接近工作。问题是您需要将所有者设置为提示视图,但您正在尝试在类方法中执行此操作。类方法中的self 是类,而您需要self 是类的instance。您的 fromNib 方法不需要是类方法,它可以是实例方法。这是一个例子:

    extension UIView {
        func createView<T : UIView>() -> T? {
            let type = type(of:self)
            guard
                let nibs = Bundle(for: type).loadNibNamed(String(describing: type), owner: self, options: nil),
                let nib = nibs.last
                else {
                    return nil
            }
    
            return nib as? T
        }
    }
    

    现在在您的视图设置中,您可以使用if let view = createView(){ //... }

    【讨论】:

    • 是的,这就是我最初想要实现的目标,无论是静态方法还是实例方法,重要的是在 UIView 上扩展它。
    • 对于那些对为什么从主包加载不适用于实时预览但仍然在运行时工作感兴趣的人,看看这个:stackoverflow.com/a/24604071/3402095
    • 很好的答案 Ben,很好的一段代码。效果很好。
    猜你喜欢
    • 1970-01-01
    • 2012-10-31
    • 2011-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多