Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading a XIB file to a UIView Swift

I am trying to load my XIB file into a UIView but I am having some trouble. I have the required override functions but they seem to be crashing. Saying this error, warning:

could not load any Objective-C class information. This will significantly reduce the quality of type information available.

I was wondering if someone could show me how to properly load the XIB file into a 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);  
    }
}
like image 254
Jimmy lemieux Avatar asked Feb 26 '16 19:02

Jimmy lemieux


People also ask

How do I load a xib file with attached Viewcontroller in Swift?

xib file. To navigate via UINavigationController you should use this method: @IBAction func handleButtonAction(_ sender: UIButton) { let viewControllerInXib = ViewControllerInXib(nibName: "ViewControllerXibName", bundle: nil) if let navigationController = navigationController { navigationController.

How do I load a custom view in storyboard?

Using a custom view in storyboards Open up your story board and drag a View (colored orange below for visibility) from the Object Library into your view controller. Set the view's custom class to your custom view's class. Create an outlet for the custom view in your view controller.


11 Answers

I uses this in one of our projects, might be useful to you

import UIKit

class RegisterPageView: UIView {
    
        class func instanceFromNib() -> RegisterPageView {
            return UINib(nibName: "RegisterPageView", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as! RegisterPageView
        }
}
 
like image 69
Peter Combee Avatar answered Oct 23 '22 19:10

Peter Combee


Using Swift 3.0

let viewFromNib: UIView? = Bundle.main.loadNibNamed("NibName", 
    owner: nil, 
    options: nil)?.first
like image 35
Morgan Wilde Avatar answered Oct 23 '22 19:10

Morgan Wilde


Improved DevAndArtist UIView extension

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

Usage

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

External Objects discussion

like image 36
Ako Avatar answered Oct 23 '22 17:10

Ako


Here is my approach (written in 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 {}

Now I simply can create any UIView subclass from a Xib (assuming there is one) like so MyCustomView.instantiateFromXib(). Remember to name your Xib file exactly as your UIView subclass and set the type of the main view in that Xib file correctly.


As soon as SE-0068 will be implemented one could drop the protocol and move the function directly into the UIView extension.


Just a note: The original post uses a commonly used pattern with a nested view. IMHO this is a bad pattern which does not utilize the resources and only creates unnecessary view hierarchy.

like image 37
DevAndArtist Avatar answered Oct 23 '22 17:10

DevAndArtist


Swift 4.x

let myView = Bundle.main.loadNibNamed("yourXibView", owner: nil, options: nil)![0] as! UIView
like image 26
Hooda Avatar answered Oct 23 '22 18:10

Hooda


for swift 3

class YourClass:  UIView {
    class func instanceFromNib() -> YourClass {
        return UINib(nibName: "YourClassNibName", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! YourClass
    }
}
like image 32
KIO Avatar answered Oct 23 '22 18:10

KIO


In my project I implemented the following (very similar to Peter's Solution)

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)
    }
}

To use, you just simply implement the protocol:

class MyView: UIView, InterfaceBuilderInstantiable
{
    // The rest

And if your nib is the same name as your class (MyView.xib), you're set: the default implementation of the protocol looks for a nib with the same name as the class in the main bundle.

Of course, if your nib is in another bundle or has a different name you can override the associatedNib and return your own nib.

like image 30
Can Avatar answered Oct 23 '22 17:10

Can


Usually I use the following way to load a xib file owned by a custom UIView:

NSBundle.mainBundle().loadNibNamed(nibName, owner: self, options: nil)[0];
like image 34
nsinvocation Avatar answered Oct 23 '22 17:10

nsinvocation


Swift 4.x

This is finally how I did it This is not in the customView itself. I put the code where the ViewController is loading the customView.

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)
    }
like image 25
chainstair Avatar answered Oct 23 '22 17:10

chainstair


let xibView = NSBundle.mainBundle().loadNibNamed("NameXibView", owner: nil, options: nil)[0] as! UIView
like image 23
Andres Marin Avatar answered Oct 23 '22 18:10

Andres Marin


Swift 5.x

let loadMusicView = Bundle.main.loadNibNamed("MusicView", owner: nil, options: nil)![0] as? MusicView
loadMusicView?.frame = controlsMainView.bounds
loadMusicView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
controlsMainView.addSubview(loadMusicView!)

//if you have variables in your .xib file access those variables like this
loadMusicView.yourVariableName = .....
like image 21
Naresh Avatar answered Oct 23 '22 19:10

Naresh