Skip to content

Instantly share code, notes, and snippets.

@bwhiteley
Last active March 17, 2024 13:10
Show Gist options
  • Star 95 You must be signed in to star a gist
  • Fork 17 You must be signed in to fork a gist
  • Save bwhiteley/049e4bede49e71a6d2e2 to your computer and use it in GitHub Desktop.
Save bwhiteley/049e4bede49e71a6d2e2 to your computer and use it in GitHub Desktop.
Initialize Swift subclass of UIView, designed in .xib
// Create CustomView.xib, set File's Owner to CustomView.
// Link the top level view in the XIB to the contentView outlet.
class CustomView : UIView {
@IBOutlet private var contentView:UIView?
// other outlets
override init(frame: CGRect) { // for using CustomView in code
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) { // for using CustomView in IB
super.init(coder: aDecoder)
self.commonInit()
}
private func commonInit() {
Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)
guard let content = contentView else { return }
content.frame = self.bounds
content.autoresizingMask = [.flexibleHeight, .flexibleWidth]
self.addSubview(content)
}
}
@y00s
Copy link

y00s commented Dec 14, 2015

Hi,
Thanks for code.

I tried to use it as following :

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

    self.commonInit()
}

required public init?(coder aDecoder: NSCoder)
{
    super.init(coder: aDecoder)
    self.commonInit()
}

private func commonInit() {
    NSBundle(forClass: CustomController.self).loadNibNamed("CustomController", owner: self, options: nil)
    guard let content = view else { return }
    content.frame = self.bounds
    content.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
    self.addSubview(content)
}

but every time that loadNibName line done it calls to - init(coder) function
and it makes infinity loop with commonInit..

please help

---- EDIT-----

I resolved my issue
In the document outline, you should only set the File's Owner to your custom class,
and leave the top level "view" object below as nothing.

@dnsmob
Copy link

dnsmob commented Feb 9, 2016

👍 🍻

@jackywang135
Copy link

Why do you need to addSubview when the IBOutlet already makes the contentView a subview of the superview?

Copy link

ghost commented Mar 4, 2016

I did everything and it runs fine. However, my constraints set in the xib file don't carry over properly. I have a label that is supposed to be 8 from the top and it's actually something like 30 from the top. I'm setting the custom view as a tableview tableheaderview.

@jasonwiener
Copy link

thanks a ton for this...

@leancmscn
Copy link

not support autolayout for different devices

@nicolas-miari
Copy link

Great, thanks for posting this.

@guttentag
Copy link

great stuff!
works great!

@leandropjp
Copy link

leandropjp commented Nov 23, 2016

Great, Thanks!

@joelklabo
Copy link

Thanks! It's crazy how difficult it is to find information on how to do this

@girishvr
Copy link

girishvr commented Jan 4, 2017

Use this to break the infinite loop.

 required init?(coder aDecoder: NSCoder) { // for using CustomView in IB
        super.init(coder: aDecoder)
         if self.subviews.count == 0{
             self.commonInit()
         }
    }

@dbleiweiss13
Copy link

how do you link top level view in the xib to the content view outlet

@Sesadev
Copy link

Sesadev commented Mar 25, 2017

class CustomHeader: UIView {

var view:UIView!

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

required init(coder aCoder: NSCoder) {
    super.init(coder: aCoder)!
    setup()
}

func setup() {
    view = self.loadViewFromNib()
    view.frame = bounds
    view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    addSubview(view)
}

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

Simply add class type (Ex.CustomHeader) in Xib file of where you are going to use this custom class. it worked fine for me

@itsgoofer
Copy link

Is it possible to have this in an extension (swift 3)? I don't seem to be able to come up with a working one. Ideas?

@Ohad-Maor
Copy link

Just use NibDesignable

@denis631
Copy link

denis631 commented Oct 2, 2017

Don't try to get the first view. If you do it, the iboutlets won't be set anyway, which is not what you what. Rather do this:

import UIKit

class CustomView: UIView {
    @IBOutlet weak var contentView: UIView?
    @IBOutlet weak var anotherSubviewOfContentViewHere: UIView?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        nibSetup()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        nibSetup()
    }
    
    func nibSetup() {
        Bundle.main.loadNibNamed(String(describing: CustomView.self), owner: self, options: nil)
        
        guard let contentView = contentView else { return }
        self.addSubview(contentView)
    }
}

@trupti2088
Copy link

It goes into an infinite loop. No solution seems to be working for creating a simple custom UIView!!!!!

@yunchiri
Copy link

It goes into an infinite loop too

@ovyhlidal
Copy link

Infinite loop is caused by not setting FileOwner or remove custom class name in top level view. Top level view should be just UIView. All outlets has to be connected from FileOwner.

@StarWars
Copy link

StarWars commented May 1, 2018

Here is the setup for all you guys experiencing infinite loop:

  1. Open your xib file
  2. Press File's Owner -> Utilities pane (right Xcode pane) -> 3rd "tab" -> Custom Class -> Set Class to the name of your *.swift/*.m file
  3. Press topmost view -> remove Custom Class in the same menu as in step 2.
  4. If your *.swift / *.m file already had the outlets configured, you'll notice, that they are not connected (you can see that in the 6th tab of the right Xcode pane). To fix that proceed to steps 5 and 6.
  5. Delete all the iboutlets you've had configured for your subviews.
  6. Connect File's Owner's outlets to your subviews

@Abdulaziz1993
Copy link

thanks for the code

@sudebsm
Copy link

sudebsm commented Sep 26, 2018

Hi all
I need to send extra two parameters in CustomView class from the viewcontroller class , How this is possible.

@Bhide
Copy link

Bhide commented Jan 31, 2019

There's a memory leak shown at 'Bundle.main.loadNibNamed'

screen shot 2019-01-31 at 11 43 18 am

@maneesh888
Copy link

I think we are on the same page, I want to create a custom view with IBOutlets. And I want to create it in such a way that it can directly use in storyboard. But it seems to impossible, when init with coder initialise a view, the IBOutlets are nil. If I use a different method using files owner , awake from nib will never execute, here. The sad part is that, the dilemma is to just load a view to screen. Anyone have a comment?

@bhavik-98
Copy link

bhavik-98 commented Apr 14, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment