Error in custom UIView class having interface loaded from .xib file - ios

I want to make a reusable UIView which I will use in several UIViewControllers.
So I added a .xib file in my project and I drawn my interface, I added a class inherited from UIView and then I set up .xib class type same as the new class I have just added.
Next I dragged a outlet for .xib's main view in corresponding .h .
In myCustomUIView class I wrote this code to load the interface from .xib but it crashes at the line where I'm trying to load the nib file. Unfortunately compiler doesn't give me any error/reason. Please help me.
-(void)awakeFromNib
{
[[NSBundle mainBundle] loadNibNamed:#"DropDownMenuViewInterface" owner:self options:nil];
[self addSubview: self.customView];
}

Did you setup File Owner for this xib?
Check my image
Instead of subclassing root view in you xib hierarchy - make the File Owner to be your view subclass

Related

Connect UIView in XIB and load it using View Controller in the Story board

I have a XYZViewController (simple UIViewController in storyboard) that is loaded up with the default view. I have a type XYZView for which I have UIView in a .xib file.
In the XYZViewController class, I have defined property for XYZView as an IBOutlet. What is tricky is I don't know how to connect this property to the UIViewController in storyboard (or UIVIew in .xib file) such that —
the IBOutlet is connected to the right UIView
the view in the xib becomes an added subview for the default view of the UIViewController.
(I under the question sounds dodgy and/or I may not have the very right way to explain it, but that's the best I could.)
EDIT: Further clarification may make it easier. I just don't want to myself say:
XYZView *xyzView = [[XYZView alloc] initWithFrame...];
or
[self.view addSubview:xyzView];
Maybe that helps.
OK, from what I tell you have the following...
XYZViewController
The code of this is in XYZViewController.h and .m files.
A .storyboard file
In the storyboard file you have a view controller that you have set the subclass to XYZViewController.
A .xib file
In the xib file you have a single view that you have defined as the subclass XYZView.
Right?
I'm guessing what you have done is the following...
In the .xib file you have laid out the XYZView and put labels, buttons, etc... on it.
The view controller is being created by the storyboard. But now you want to attach the labels and buttons to it.
Right?
If all this is correct then you have a couple of options.
The easiest option
Drop the xib file. Unless that XYZView is being used in multiple places in the app (i.e. inside different view controllers) then you should really be doing all of that layout in the storyboard. Add the buttons and labels to the XYZViewController in the storyboard.
This will then allow you to connect the IBOutlets and IBActions and it will all just work because the storyboard is creating and then setting the outlets and actions.
Next option
Because you have created the view in a xib file you have to load it from that xib file in code and then add it to you view controller.
Something like...
- (void)viewDidLoad
{
[super viewDidLoad];
self.xyzView = [[[NSBundle mainBundle] loadNibNamed:#"XYZView" owner:self options:nil] objectAtIndex:0];
[self.view addSubview:xyzView];
}
Then you can do stuff like ...
self.xyzView.someLabel.text = #"This is the text";
You still won't be able to connect outlets and actions but that's because the view controller is not being created by the xib. It's being created by the storyboard.
This can get all messy though. I'd really only recommend creating a view in a separate xib if it's something that you reuse over and over (like a 5star rating view or something).
What you absolutely can't do
OK, I think I may have thought of what you are doing.
In the storyboard you have set the subclass of the view as XYZView and you are expecting it to pick up the labels and buttons etc... that you have defined in the xib file for XYZView.
This absolutely will not work, ever.
The storyboard and the xib are completely separate objects. If you want to use them together then code is involved in loading a view from a nib and then adding it to a view controller created in a storyboard.

Add custom view in xib file

So I have a custom view created(with a xib file) and I'm trying to use it in another xib file...but it's not showing. In that xib file I have a view and I've set the custom class field to my custom view's name.
However, this view is not showing.
I don't want to draw this view programmatically, I want to use a xib file - how do I do this?
I'm not sure what code I can post up - just tell me in the comments.
I'm not aware of a method to directly drawing a custom view with a xib to another xib, but a thing you can do is:
assing the file owner to the view controller of the xib you want to put the custom one in.
assign the view as an IBOutlet of that controller.
when you need the outlet simply call: [[NSBundle mainBundle] loadNibNamed:#"your_custom_view_xib_name" owner:self options:nil];, at this point the outlet previously created will be set.
set the outlet as subview of the view

How does NSBundle set pointers to view objects in instance variables when loading a nib file?

I'm working through a book and currently adding a view to a tables header programmatically. So I've setup the XIB file added a view resized it and added two subViews/UIButtons.
Interface file:
#import <Foundation/Foundation.h>
#interface ItemsViewController : UITableViewController
{
IBOutlet UIView *headerView;
}
- (UIView *)headerView;
- (IBAction)addNewItem:(id)sender;
- (IBAction)toggleEditingMode:(id)sender;
#end
Part of my implementation:
- (UIView *)headerView
{
// If we haven't got the headerView yet
if (!headerView) {
[[NSBundle mainBundle] loadNibNamed:#"HeaderView" owner:self options:nil];
}
return headerView;
}
In the Big Nerd book it states:
“The first time the headerView message is sent to the ItemsViewController, it will load HeaderView.xib and keep a pointer to the view object in the instance variable headerView.”
What I'd like to know is how is how it sets/keeps a pointer to the view object in the headerView instance variable?
I know the nib file is being is being loaded by passing it into the loadNibName parameter as a string but how is the pointer being set to the object in my headerView instance variable?
When I connect the file owner to headerView is that like creating an instance of UIView and storing it in the headerView instance variable programmatically?
I found it really hard to word the question but I hope it makes sense after reading this post.
Kind regards
The -loadNibNamed:owner:options: method on NSBundle will read a nib file, instantiate the objects defined in it, and set any connections the nib file defines between those objects or between the loaded objects and the available proxy objects (like "File's Owner"). In this case you are passing self (the current ItemsViewController instance) as the owner argument. That ItemsViewController will then be the "File's Owner" when objects are loaded from this nib file.
If you look at the nib in Xcode you should see that one of the UIViews defined in that nib is connected to the headerView outlet of the "File's Owner". As a result when the nib is loaded it will attempt to set that headerView ivar to reference the loaded UIView object.
When I connect the file owner to headerView is that like creating an instance of UIView and storing it in the headerView instance variable programmatically?
Yes, this is equivalent to creating the view programmatically and setting the ivar yourself. You could write a method to create views on demand instead of using a nib as a factory for view objects if you prefer. Nibs are handy because they can allow you to configure view properties in a visual editor which may be easier to adjust than setting those properties progammatically. Nibs also offer a way to loosely couple the source of your view instances to the controller using those views which is convenient when you might want to switch which view your controller uses (iPad vs iPhone view, or different views for different locales).

How can I create view controller that is defined in XIB?

Sorry for perhaps noob question, guys. I'm new to iOS development.
How can I create view controller that is defined in XIB ?
When you create new class inherited from UIViewController in Xcode via "New File" and mark with XIB checkbox it creates xib file that doesn't have viewController element. But rather it has placeholder which points to UIViewController which is defined in the code.
But I see that you can create controller itself in Interface Builder and specify customClass for it.
Unfortunately it doesn't work for me. I get loaded the "EmbeddedViewController" nib but the view outlet was not set error in run-time. But I believed view property must be set by resource loader automatically since everything is defined via XIB. It works that way for TableView and its cells for example.
Could you please provide example how to do it ?
I created sample project: https://github.com/cppexpert/SampleWithNib
The controller in question is EmbeddedViewController
Create one Xib per UIViewController
Each Xib have File's Owner object for you to set UIViewController class there. Click File's Owner and choose EmbeddedViewController on it's class
Then drag main UIView not UIViewController class to there, then hook up this view with file's owner as view. UIViewController just use to drag to StoryBoard base project.
https://github.com/lequysang/gitfiles02/blob/master/SampleWithNib-master.zip
Turned out these controls exist in IB for Storyboard projects.
When you create a view controller with xib via "new file", Xcode generates an UIView and connects it with view outlet automatically. Seems like you changed something after Xcode generated the xib file. In that case you need to connect a view to the view outlet manually.
If you create a new view in xib.set the file owner to your custom class.
Or if you simply want to create a view.
Then
NSArray* test1 = [[NSBundle mainBundle] loadNibNamed:#"View" owner:self options:nil];
self.myViewFromNib = [test1 objectAtIndex:0];
Where myViewFromNib is your view object and "View" is your nib name.

Endless recursive calls to initWithCoder when instantiating xib in storyboard

In order to re-use a certain subview throughout my application (which is storyboard based), I decided to build the subview as a nib, and load it in. To do this, I have done the following:
I have a UIView subclass we can call Widget. I create a corresponding xib file, set the File owner property to my new subclass, hook up the IBOutlets.
Then, in my storyboard, I have a uiview inside of a view controller, and I set its class to the Widget class I created.
Within the widget class, I override initWithCoder, and in there load the nib as follows:
-(id)initWithCoder:(NSCoder *)aDecoder{
if ((self = [super initWithCoder:aDecoder])){
[self addSubview:[[[NSBundle mainBundle] loadNibNamed:#"Widget" owner:self options:nil] objectAtIndex:0]];
}
return self;
}
The app would crash at this point, and setting a break point here revealed that initWithCoder was being called over and over again.
It seems like I have mixed two methods for using a nib in this situation, but I'm unclear as to where I went wrong. I can throw up a stack trace if necessary, but it's basically endless nested calls to the same function.
Did you happen to set the View's "Custom Class" in your .xib file to "Widget"?
That would explain the behaviour you're seeing, because initWithCoder: is the initializer for all things loaded from a xib:
Your parent view, which contains a Widget object, is loaded from the xib
The Widget's initWithCoder: method gets called, and tries to load the Widget xib
The Widget xib contains a UIView with the Custom
Class "Widget", so again, a Widget object is being initialized with
initWithCoder:, etc.
If that is indeed the case, all you have to do is remove the "Custom Class" entry for the UIView in your Widget's xib.
I had same problem. My mistake was in empty File's Owner class. In File's Owner custom class must be NOT empty (Widget), and root view must be empty.
IBActions and IBOutlets were fine.

Resources