Close Menu
geekfence.comgeekfence.com
    What's Hot

    Designing trust & safety (T&S) in customer experience management (CXM): why T&S is becoming core to CXM operating model 

    January 24, 2026

    iPhone 18 Series Could Finally Bring Back Touch ID

    January 24, 2026

    The Visual Haystacks Benchmark! – The Berkeley Artificial Intelligence Research Blog

    January 24, 2026
    Facebook X (Twitter) Instagram
    • About Us
    • Contact Us
    Facebook Instagram
    geekfence.comgeekfence.com
    • Home
    • UK Tech News
    • AI
    • Big Data
    • Cyber Security
      • Cloud Computing
      • iOS Development
    • IoT
    • Mobile
    • Software
      • Software Development
      • Software Engineering
    • Technology
      • Green Technology
      • Nanotechnology
    • Telecom
    geekfence.comgeekfence.com
    Home»iOS Development»Custom UIView subclass from a xib file
    iOS Development

    Custom UIView subclass from a xib file

    AdminBy AdminJanuary 10, 2026No Comments7 Mins Read2 Views
    Facebook Twitter Pinterest LinkedIn Telegram Tumblr Email
    Custom UIView subclass from a xib file
    Share
    Facebook Twitter LinkedIn Pinterest Email


    Do you want to learn how to load a xib file to create a custom view object? Well, this UIKit tutorial is just for you written in Swift.

    I already have a comprehensive guide about initializing views and controllers, but that one lacks a very special case: creating a custom view using interface builder. 🤷‍♂️

    Loading xib files

    Using the contents of a xib file is a pretty damn easy task to do. You can use the following two methods to load the contents (aka. the view hierarchy) of the file.

    let view = UINib(
        nibName: "CustomView", 
        bundle: .main
    ).instantiate(
        withOwner: nil, 
        options: nil
    ).first as! UIView
    
    // does the same as above
    // let view = Bundle.main.loadNibNamed(
    //    "CustomView", 
    //    owner: nil, 
    //    options: nil
    // )!.first as! UIView 
    
    view.frame = self.view.bounds
    self.view.addSubview(view)
    

    The snippet above will simply instantiate a view object from the xib file. You can have multiple root objects in the view hierarchy, but this time let’s just pick the first one and use that. I assume that in 99% of the cases this is what you’ll need in order to get your custom designed views. Also you can extend the UIView object with any of the solutions above to create a generic view loader. More on that later… 😊

    This method is pretty simple and cheap, however there is one little drawback. You can’t get named pointers (outlets) for the views, but only for the root object. If you are putting design elements into your screen, that’s fine, but if you need to display dynamic data, you might want to reach out for the underlying views as well. 😃

    Custom views with outlets & actions

    So the proper way to load custom views from xib files goes something like this:

    Inside your custom view object, you instantiate the xib file exactly the same way as I told you right up here. 👆 The only difference is that you don’t need to use the object array returned by the methods, but you have to connect your view objects through the interface builder, using the File’s Owner as a reference point, plus a custom container view outlet, that’ll contain everything you need. 🤨

    // note: view object is from my previous tutorial, with autoresizing masks disabled
    class CustomView: View {
    
        // this is going to be our container object
        @IBOutlet weak var containerView: UIView!
    
        // other usual outlets
        @IBOutlet weak var textLabel: UILabel!
    
        override func initialize() {
            super.initialize()
    
            // first: load the view hierarchy to get proper outlets
            let name = String(describing: type(of: self))
            let nib = UINib(nibName: name, bundle: .main)
            nib.instantiate(withOwner: self, options: nil)
    
            // next: append the container to our view
            self.addSubview(self.containerView)
            self.containerView.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                self.containerView.topAnchor.constraint(equalTo: self.topAnchor),
                self.containerView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
                self.containerView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
                self.containerView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
            ])
        }
    }
    

    So the initialize method here is just loading the nib file with the owner of self. After the loading process finished, your outlet pointers are going to be filled with proper values from the xib file. There is one last thing that we need to do. Even the views from the xib file are “programmatically” connected to our custom view object, but visually they aren’t. So we have to add our container view into the view hierarchy. 🤐

    Custom UIView subclass from a xib file

    If you want to use your custom view object, you just have to create a new instance from it – inside a view controller – and finally feel free to add it as a subview!

    One word about bounds, frames aka. springs and struts: fucking UGLY! That’s two words. They are considered as a bad practice, so please use auto layout, I have a nice tutorial about anchors, they are amazing and learning them takes about 15 minutes. 😅

    class ViewController: UIViewController {
    
        weak var customView: CustomView!
    
        override func loadView() {
            super.loadView()
    
            let customView = CustomView()
            self.view.addSubview(customView)
            NSLayoutConstraint.activate([
                customView.topAnchor.constraint(equalTo: self.view.topAnchor),
                customView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
                customView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
                customView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
            ])
            self.customView = customView
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.customView.textLabel.text = "Lorem ipsum"
        }
    }
    

    That’s it, now you have a completely working custom UIView object that loads a xib file in order to use it’s contents. Wasn’t so bad, right? 🤪

    One more extra thing. If you don’t like to handle views programmatically or you simply don’t want to mess around with the loadView method, just remove it entirely. Next put the @IBOutlet keyword right before your custom view class variable. Open your storyboard using IB, then drag & drop a new UIView element to your controller and connect the custom view outlet. It should work like magic. 💫

    Storyboard

    I promised outlets and actions in the heading of this section, so let’s talk a little bit about IBActions. They work exactly the same as you’d expect them with controllers. You can simply hook-up a button to your custom view and delegate the action to the custom view class. If you want to forward touches or specific actions to a controller, you should use the delegate pattern or go with a simple block. 😎

    Ownership and container views

    It is possible to leave out all the xib loading mechanism from the view instance. We can create a set of extensions in order to have a nice view loader with a custom view class from a xib file. This way you don’t need a container view anymore, also the owner of the file can be left out from the game, it’s more or less the same method as reusable cells for tables and collections created by Apple. 🍎

    You should know that going this way you can’t use your default UIView init methods programmatically anymore, because the xib file will take care of the init process. Also if you are trying to use this kind of custom views from a storyboard or xib file, you won’t be able to use your outlets, because the correspondig xib of the view class won’t be loaded. Otherwise if you are trying to load it manyally you’ll run into an infinite loop and eventually your app will crash like hell. 😈

    import UIKit
    
    extension UINib {
        func instantiate() -> Any? {
            return self.instantiate(withOwner: nil, options: nil).first
        }
    }
    
    extension UIView {
    
        static var nib: UINib {
            return UINib(nibName: String(describing: self), bundle: nil)
        }
    
        static func instantiate(autolayout: Bool = true) -> Self {
            // generic helper function
            func instantiateUsingNib(autolayout: Bool) -> T {
                let view = self.nib.instantiate() as! T
                view.translatesAutoresizingMaskIntoConstraints = !autolayout
                return view
            }
            return instantiateUsingNib(autolayout: autolayout)
        }
    }
    
    class CustomView: UIView {
    
        @IBOutlet weak var textLabel: UILabel!
    }
    
    // usage (inside a view controller for example)
    // let view = CustomView.instantiate()
    

    Just like with table or collection view cells this time you have to set your custom view class on the view object, instead of the File’s Owner. You have to connect your outlets and basically you’re done with everything. 🤞

    ownership

    From now on you should ALWAYS use the instantiate method on your custom view object. The good news is that the function is generic, returns the proper instance type and it’s highly reusable. Oh, btw. I already mentioned the bad news… 🤪

    There is also one more technique by overriding awakeAfter, but I would not rely on that solution anymore. In most of the cases you can simply set the File’s Owner to your custom view, and go with a container, that’s a safe bet. If you have special needs you might need the second approach, but please be careful with that. 😉



    Source link

    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email

    Related Posts

    A Deep Dive into SwiftData migrations – Donny Wals

    January 24, 2026

    AI, find me some work…

    January 23, 2026

    Swift adapter design pattern – The.Swift.Dev.

    January 22, 2026

    Text is not visible when the button is in disabled state

    January 21, 2026

    What’s New in SwiftUI for iOS 18

    January 19, 2026

    WWDC 2023: A Reflection on Apple’s “Spatial Computing” Journey

    January 17, 2026
    Top Posts

    Understanding U-Net Architecture in Deep Learning

    November 25, 202511 Views

    Hard-braking events as indicators of road segment crash risk

    January 14, 20269 Views

    Microsoft 365 Copilot now enables you to build apps and workflows

    October 29, 20258 Views
    Don't Miss

    Designing trust & safety (T&S) in customer experience management (CXM): why T&S is becoming core to CXM operating model 

    January 24, 2026

    Customer Experience (CX) now sits at the intersection of Artificial Intelligence (AI)-enabled automation, identity and access journeys, AI-generated content…

    iPhone 18 Series Could Finally Bring Back Touch ID

    January 24, 2026

    The Visual Haystacks Benchmark! – The Berkeley Artificial Intelligence Research Blog

    January 24, 2026

    Data and Analytics Leaders Think They’re AI-Ready. They’re Probably Not. 

    January 24, 2026
    Stay In Touch
    • Facebook
    • Instagram
    About Us

    At GeekFence, we are a team of tech-enthusiasts, industry watchers and content creators who believe that technology isn’t just about gadgets—it’s about how innovation transforms our lives, work and society. We’ve come together to build a place where readers, thinkers and industry insiders can converge to explore what’s next in tech.

    Our Picks

    Designing trust & safety (T&S) in customer experience management (CXM): why T&S is becoming core to CXM operating model 

    January 24, 2026

    iPhone 18 Series Could Finally Bring Back Touch ID

    January 24, 2026

    Subscribe to Updates

    Please enable JavaScript in your browser to complete this form.
    Loading
    • About Us
    • Contact Us
    • Disclaimer
    • Privacy Policy
    • Terms and Conditions
    © 2026 Geekfence.All Rigt Reserved.

    Type above and press Enter to search. Press Esc to cancel.