将一个XIB文件加载到UIView中 Swift

29

我试图将XIB文件加载到UIView中,但是遇到了一些问题。我有所需的重写函数,但它们似乎会崩溃。提示错误如下:

无法加载任何Objective-C类信息。这将极大地降低可用的类型信息的质量。

我想知道是否有人可以向我展示如何正确地将XIB文件加载到UIView中。

import UIKit

class Widget: UIView {

    let view = UIView()

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

        //call function

        loadNib()

    }

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

        loadNib()

        //fatalError("init(coder:) has not been implemented")
    }

    func loadNib() {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: "nib", bundle: bundle)
        let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
        view.frame = bounds
        view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        self.addSubview(view);  
    }
}

你的XIB文件真的被命名为“nil”了吗? - Lukesivi
看起来运行正常...具体是哪一行导致了崩溃? - Pradeep K
这个回答解决了你的问题吗?在Swift中从nib加载UIView - Top-Master
14个回答

49

我在我们的项目中使用了这个,也许对你有用

import UIKit

class RegisterPageView: UIView {
    
        class func instanceFromNib() -> RegisterPageView {
            return UINib(nibName: "RegisterPageView", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as! RegisterPageView
        }
}
 

它不适用于 thisView.alpha = 0thisView.superview - Jack

23

使用Swift 3.0

let viewFromNib: UIView? = Bundle.main.loadNibNamed("NibName", 
    owner: nil, 
    options: nil)?.first

18

改进的DevAndArtist UIView扩展

public extension UIView
{
    static func loadFromXib<T>(withOwner: Any? = nil, options: [UINib.OptionsKey : Any]? = nil) -> T where T: UIView
    {
        let bundle = Bundle(for: self)
        let nib = UINib(nibName: "\(self)", bundle: bundle)

        guard let view = nib.instantiate(withOwner: withOwner, options: options).first as? T else {
            fatalError("Could not load view from nib file.")
        }
        return view
    }
}

使用方法

let view = CustomView.loadFromXib()
let view = CustomView.loadFromXib(withOwner: self)
let view = CustomView.loadFromXib(withOwner: self, options: [UINibExternalObjects: objects])

External Objects discussion


14

这是我的方法(用Swift 3.1编写):

protocol XibDesignable : class {}

extension XibDesignable where Self : UIView {

    static func instantiateFromXib() -> Self {

        let dynamicMetatype = Self.self
        let bundle = Bundle(for: dynamicMetatype)
        let nib = UINib(nibName: "\(dynamicMetatype)", bundle: bundle)

        guard let view = nib.instantiate(withOwner: nil, options: nil).first as? Self else {

            fatalError("Could not load view from nib file.")
        }
        return view
    }
}

extension UIView : XibDesignable {}

现在我可以通过Xib轻松创建任何UIView子类(假设有一个),方法如下MyCustomView.instantiateFromXib()。请记得将您的Xib文件与UIView子类命名相同,并正确设置该Xib文件中主视图的类型。

一旦SE-0068被实现,就可以放弃协议并将函数直接移入UIView扩展中。


注:原帖使用了常见的嵌套视图模式。在我看来,这是一种不好的模式,它没有充分利用资源,只会创建不必要的视图层次结构。


我喜欢这种方法。在我的情况下,.xib文件仅包含当前类的一个视图,而guard let view = nib.instantiate(withOwner: nil, options: nil).last崩溃了,因为.last返回了nil。但出于某种原因,guard let view = nib.instantiate(withOwner: nil, options: nil)[0]却非常好用。只需将.last更改为[0]即可。 - m_katsifarakis
1
我的示例中没有 .last。此外,如果数组确实包含某些内容,则 .first 不能为 nil。如果数组为空,[0] 也会崩溃。 - DevAndArtist
@DevAndArtist 我使用了你的代码,但是我遇到了内存泄漏问题。 - Pradip Sutariya

10

Swift 4.x

let myView = Bundle.main.loadNibNamed("yourXibView", owner: nil, options: nil)![0] as! UIView

7

针对 Swift 3

class YourClass:  UIView {
    class func instanceFromNib() -> YourClass {
        return UINib(nibName: "YourClassNibName", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! YourClass
    }
}

你能填写更多的空吗?那应该放在哪里,它被调用在哪里?我已经花了比我愿意承认的时间来折腾这个问题了,但我找到的所有资料都是过时的Swift或Objective-C。这似乎是一个简单的练习,但我太蠢了,无法弄清楚。 - Adrian

4
在我的项目中,我实现了以下内容(与Peter的解决方案非常相似)。
import UIKit

// MARK: - Protocol Declaration

public protocol InterfaceBuilderInstantiable
{
    /// The UINib that contains the view
    ///
    /// Defaults to the swift class name if not implemented
    static var associatedNib : UINib { get }
}

// MARK: - Default Implementation

extension InterfaceBuilderInstantiable
{
    /// Creates a new instance from the associated Xib
    ///
    /// - Returns: A new instance of this object loaded from xib
    static func instantiateFromInterfaceBuilder() -> Self
    {
        return associatedNib.instantiate(withOwner:nil, options: nil)[0] as! Self
    }

    static var associatedNib : UINib
    {
        let name = String(describing: self)
        return UINib(nibName: name, bundle: Bundle.main)
    }
}

要使用它,您只需简单地实现该协议:

class MyView: UIView, InterfaceBuilderInstantiable
{
    // The rest

如果你的nib文件名和类名相同(MyView.xib),那么你可以使用默认实现的协议,在主包中查找与类名相同的nib文件。

当然,如果你的nib文件在另一个包中或者文件名不同,可以覆盖associatedNib方法并返回自己的nib文件。


我已经使用了你的方法,但它导致了应用程序中的内存泄漏。 - Pradip Sutariya

3
通常我使用以下方式加载由自定义UIView拥有的xib文件:
NSBundle.mainBundle().loadNibNamed(nibName, owner: self, options: nil)[0];

2

Swift 4.x

最终我是这样做的: 这不在自定义视图本身中。我将代码放置在ViewController加载自定义视图的位置。

import UIKit

class StartMenuViewController: UIViewController {

    @IBOutlet weak var customView: CustomView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let myView = Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)![0] as! UIView
        customView .addSubview(myView)
    }

1
let xibView = NSBundle.mainBundle().loadNibNamed("NameXibView", owner: nil, options: nil)[0] as! UIView

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接