There seems to be a lot of confusion around custom views on iOS that can be used both at compile time under Interface Builder and at runtime.
Even though a lot of posts exist that show how to design a UIView with a custom hierarchy using Interface Builder, there seems to be unnecessary complexity on what comes next.
1. Design the look and feel and view hierarchy in Interface Builder
The first thing to do is create a xib file (TBView.xib) as to design in Interface Builder the look and feel of your custom view along with its hierarchy.
By convention, this nib should hold a single top-level view.
The code to load any views that are in a xib file is the following.
Where views is a collection of every top-level view in the xib file. (in this case a single one)
Will come back later to see what role the owner plays in loading the view.
2. Create a subclass of UIView as your custom view
In order to use the above look and feel in your custom view and be able to do so under Interface Builder^1 you need to create a subclass of UIView.
By convention, the name of your subclass should be the same as the xib file.
3. Using it at compile time under Interface Builder
In your UIViewController's xib, drag a view and set the "Class" as "TBView" in the "Custom Class" section under "Identity Inspector". (CMD+OPTION+3)
By convention, this view should have the same size as the look and feel design.
Any view in a nib file that is part of the view hierarchy is initialised using NSCoding#initWithCoder: hence this is the spot where you load the #view from the xib and add it as a subclass.
Notice how we are using the name of the class, which is the same as the xib by convention to load the view.
This is how the hierarchy looks like.
$0 = 0x0756c810 <TBView: 0x756bf50; frame = (0 0; 320 274); autoresize = W+H; layer = <CALayer: 0x756bfd0>> | <UIView: 0x756c050; frame = (0 0; 320 274); autoresize = RM+BM; layer = <CALayer: 0x756c0b0>> | | <UILabel: 0x756ca70; frame = (0 126; 320 21); text = 'Hello World'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x756c0e0>>
4. Using it at runtime given a frame
Simply override UIView#initWithFrame: and use the same code to load the view from the xib and add it in the hierarchy.
You can now create a new instance of that view as usual.
TBView *view = [[TBView alloc] initWithFrame:frame];
5. File's Owner and IBOutlets
If you need to keep references to any of the views in the xib, you can use the custom view as the File's Owner and define any IBOutlets as properties of that class.
As part of loading the views from the xib, the view will have its IBOutlets set.
By convention, the custom class should be the File's Owner thus keeping all related code in a single class that can be reused.
Here is a macro that you can use in both initalisers to load a single view hierarchy that is available in the main bundle.
NSNibAwaking Protocol Reference
^1: You can equally load the top-level view as designed in Interface Builder and use it at compile time.