UIView shouldn’t be File’s Owner
Tags: ios, xib, filesowner, uiview
Published: 2020-03-22 14:20:26

---
title: UIView shouldn’t be File’s Owner
published: true
description: Reason why UIView can’t be a File’s Owner
tags: iOS,xib,FilesOwner,uiview
---

I want to correct the widely spread practice of setting `UIView` as `File’s Owner` for `Xib` files.

Checkout [Apple Doc](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html) and see what `File’s Owner` is for.

> Typically, you use outlets in the File’s Owner object to store references to the top-level objects of a nib file.

What’s `top-level object`? Same document defines `top-level object` as:

> The top-level objects are the subset of these objects that do not have a parent object. The top-level objects typically include only the windows, menu bars, and custom controller objects that you add to the nib file.

Does `UIView` qualify for the job? No! `UIView` may have no parents (because `UIView` is the top object in `xib`) but it’s neither windows, menu bars nor controller object. 

Some may argue that it may be technically unqualified but it performs perfectly!

Does it?

No it doesn’t. It works poorly. Here’s why

The mere idea is structural paradox. An `.xib` file is supposed to have multiple objects and each object can be a different type of `UIView` class. But there can be only one `File’s owner` for an `.xib` file. So it means a `.xib` is one kind of `UIView` and at the same time, a multiple kinds of `UIView`? That can’t be right can it?

This paradox leads to the undesirable consequence: the `contentView` aka the wrapper view. Firstly, it gives you some extra works of making every UI components to be under the `contentView`. Secondly, It forces you to use `contentView` instead of `self`. Thirdly, and mostly, it prevents data structure from conveying it’s UI structure. Data structure is always better when it is conveying it’s UI structure and that's what declarative UI is all about. Take SwiftUI. Apple is moving to SwiftUI where such `contentView` kind of ad-hoc would never exist.

# Right way to make reusable `Xib` For `UIView`

Let me walk you through a sample project. 

This is the conventional structure:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vsm98i65qvus6p3fnhfb.jpeg)

In this sample we will employ this new structure:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/d34u0efxrhm96e6v0vs8.jpeg)

* File’s owner will be left vacant.
*  The outlets will be served through `MyView` class instead of File’s Owner.
* `contentView` will be gone.
* It will keep all the utilities of being able to be called in storyboard and instantiated anywhere in code.
* It will enable you to have multiple views in single .xib file.

Sample project is available here: 
{% github ingun37/xib4StoryboardSample %}

Define custom UIView class with some outlets.

```swift
class MyView: UIView {
    @IBOutlet weak var subView1:UIView!
    @IBOutlet weak var subView2:UIView!

    //This is helper function so you can instantiate MyView like
    //let view = MyView.loadViewFromNib()
    static func loadViewFromNib() -> MyView {
        let bundle = Bundle(for: self)
        let nib = UINib(nibName: "MyViews", bundle: bundle) //“MyViews” is name of xib file
        return nib.instantiate(withOwner: nil, options: nil).first {
            ($0 as? UIView)?.restorationIdentifier == "1"
        }! as! MyView //You will set restorationIdentifier later
    }
}
```

Create an `Xib` With an view object. Make some subviews that will be connected to outlets. Set the object’s class to `MyView`.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/orht1ke9sbdb72tr0zb2.jpeg)

Connect the outlets 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/80nclqyszn1m8zeieqst.jpeg)

Set restoration ID. This is for identification among view objects in same `.xib`. You wouldn’t need it if there were only one view object in the Xib.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/g1xos9t2dunu15qxlq3q.jpeg)

Now you are all set to instantiate from anywhere in code.

```swift
let view = MyView.loadViewFromNib()
```

I’ll get to how to call it from storyboard in a moment but before that, let me tell you first that I’ll be using a *kind of wrapper view* and let me explain this seemingly hypocritical discrepancy between my previous contempt for the idea of using `contentView` and the following usage of *kind of wrapper view*.

This time it’s very different. This *kind of wrapper view* is not just a hack or ad-hoc like it was in the conventional way. This time, it exists only for modularization of storyboard adaptation and it will never bother you throughout the development once set because:
* This time the contentView only exists in code. It will not require to have a body in any UI builder file. In other words it will not affect our `.xib` or `.storyboard` file.
* In fact, it doesn’t even exist in `MyView` class. We will define another class for, once again, modularization of storyboard adaptation at minimum code. Don’t understand? It will come clear once you see the following sample.
* Since it’s seperated into another class, it won’t affect data structure either. You don’t have to write `contentView.-` everytime to access it’s subcomponent in the code.

With that in mind, here’s how to use it with storyboard.

Define a wrapper class

```swift
class StoryMyView1:UIView {
    var contentView:MyView
    required init?(coder aDecoder: NSCoder) {
        contentView = MyView.loadViewFromNib()
        super.init(coder: aDecoder)
        contentView.frame = bounds
        addSubview(contentView)
    }
}
```

That’s it! You can use it in .storyboard just like any other views

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gapkuse9yyvrhv7gj14k.jpeg)

Don’t forget you can now have multiple views in single `.xib`. (Use restorationID for identification)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/12coxhyu5lopdcv5r50v.jpeg)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8hdhnux9taeeaoqy6ks1.jpeg)