How to get a reference to an object in a .nib file? - ios

so far I have done most view programming in code, but it really is cumbersome to position buttons perfectly in code. I searched for some time, maybe I'm using the wrong words for my search? Anyway, I created a UI in a nib file, it has several buttons. I loaded the .nib file into my view like this:
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:#"UCMenuView" owner:self options:nil];
UIView *menuView = [nibViews objectAtIndex:0];
self.delegate = (id<UCMapviewDelegate>)delegate;
// another controller does the view switching, so I'm sending him the view
[self.delegate pushView:menuView];
This is 'fine'. But I don't understand how I get a pointer to my buttons. I know about IBOutlet, but how do I connect them to the elements in the .nib? How would I connect this #property (strong, nonatomic) IBOutlet UIButton *calendar;
to a specific button in the .nib?
I tried to ctrl-drag (from that little points on the left side of the #property, but that does not work (from neither side). Excuse me if this is an easy question, but I couldn't find a clear explanation
thanks for your help

Instead of just a UIView *menuView, you need to create a custom
UIView subclass for that, e.g. UCMenuView. Define your properties on this custom
class.
Open your .xib file in the editor, select the File's Owner in
the left column and set its Custom Class in the identity
inspector to UCMenuView.
Right-click the File's Owner in the left column, and connect
your IBOutlets.

Check out this tutorial:
http://developer.apple.com/library/ios/#documentation/IDEs/Conceptual/Xcode4TransitionGuide/InterfaceBuilder/InterfaceBuilder.html
or
http://www.hongkiat.com/blog/ios-development-guide-part2-your-first-app/
Kind regards,
Bo

See Apple's documentation: Creating and Connecting an Outlet and more generally Designing User Interfaces in Xcode.

Related

Showing a content of a UIView loaded from a xib in a storyboard

Current Setup
I have a subclass of a UIView that loads a content from a xib file - call it a XibOwnerClass. Also, among other classes, there is a class called Triangle which helps me to create triangles with or without a border, with different stroke or fill color etc. That class is designable in storyboard and some of its properties are defined as IBInspectable.
Currently, in my xib file, I use this triangle view and setup its inspectable properties through IB. And that is really cool and convenient... So if I look into xib, I will actually see the triangle view among other views.
So, lets go further. In order to use this XibOwnerClass, I drag the UIView element to the storyboard, and change its custom class to XibOwnerClass, so I get my designable properties specific for XibOwnerClass. So, I can setup all things in IB and when I run the app, everything works.
The problem
Even if this works, I wonder if there is a way, to have multiple views (of class XibOwnerClass) dragged on a storyboard, and to be able to configure all of them individually trough Interface Builder?
Currently when I drag the UIView and change its custom class to XibOwnerClass I see nothing. I mean, the view is there, and it has its standard properties + inspectable properties. But I can't see triangles defined in xib in this new view. Is there a way to do this?
I am aware that xib is reused in my case (and it is meant to be used like that), so if I change something in a xib, all views that load from it will be affected. But is there a way multiple views to load from the same xib, but when loaded, to see them & setup them individually?
Here is how I load from xib:
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
if ((self = [super initWithCoder:aDecoder])){
UIView *myView = [[[NSBundle mainBundle] loadNibNamed:#"MyXib" owner:self options:nil] firstObject];
if (myView){
myView.frame = CGRectMake(myView.frame.origin.x, myView.frame.origin.y, self.frame.size.width, self.frame.size.height);
[self addSubview:myView];
//Initialize other stuff
[self commonInit];
}
}
return self;
}
Then in awakeFromNib: I use the values of inspectable properties...
EDIT:
Also I don't have initWithFrame: implemented, but I thought that it is not needed if load from nib (because it is not executed). But maybe this is needed while design time ?
can't really say what's wrong when you don't share class codes. but i guess you didnt use prepareForInterfaceBuilder. in your XibOwnerClass override prepareForInterfaceBuilder and call setups for view inside it for example change background colour or so.
override func prepareForInterfaceBuilder() {
//prepare setups or things to show in storyboard
}
Okay, I have solved it. It turned out that I shouldn't use Main Bundle but rather bundle for that class, like described here.
So here is the code:
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
#Mohammadalijf's answer in general is correct. It is just not a direct solution for my issue. But later on, when I fixed bundle thing, I used prepareForInterfaceBuilder like he said, and initialized things there so everything was available at design time.
Some useful stuff related to all this can be found here as well.

Not sure how to setup view object and connect with IBOutlet code

I am trying trying to copy all of the functionality of this example app provided by Apple called AVCam: https://developer.apple.com/library/ios/samplecode/AVCam/Introduction/Intro.html#//apple_ref/doc/uid/DTS40010112-Intro-DontLinkElementID_2
I am 99% done with copying this code, but I just have one final problem. I have an IBOutlet statement that looks like this: #property (nonatomic, weak) IBOutlet MediaCapturePreviewView *previewView;
According to the Apple sample code, this outlet is supposed to be connected to a View object that has been placed on top of the normal/default view.
Here is a screenshot of what the Connections Inspector looks like in the Apple example:
You will notice that the IBOutlet called "previewView" has been connected to something called the "Cam Preview View".
Also, in this screenshot, you can see that I am able to select this View object by itself and that it shows a Referencing Outlet in it's connections inspector for the same IBOutlet and View Object:
My problem is that I cannot get the IBOutlet code to connect to this View Object. I have tried the normal behavior of clicking and dragging to make the connections but it just wants to create a new outlet. It will not let me connect to the outlet that I have already created.
I have been playing with this for 2 hours now and just can't get it to work like Apple's sample code.
Any help is greatly appreciated thank you.
In your .xib file, make sure that UIView class is assigned as AVCamPreviewView instead of UIView.
A few possible solutions:
Save the file with the IBOutlet you're trying to connect up (the source code, not the IB)
Clean, rebuild
Restart Xcode.

UIView with Separated .h, .m and xib files

I want to create a UIView that will appear in several different UIViewControllers upon user action. For example, a "How To" pop view that whenever the user clicks on a "?" button it pops holding the relevant information about the specific action the user is interested in. The view may also have other elements like a "done" button and a UITextView that will hold the text, etc...
Intuitively, it makes me think of creating a separated UIView with .h, .m and xib files and have each UIViewController that requires this UIView will simply alloc+init it and do [self.view addSubView:flexUIView] or insert it with animation. Well... it doesn't work...
I couldn't find any tutorial that explains how to do something like that.
Is anyone familiar with this approach and have some directions?
If not, what is the common approach for such a scenario?
Alloc init will not load the nib of your custom UIView as in ViewControllers.
You should load the nib using the below code after alloc init
Suppose you have CustomView.h, CustomView.m, CustomView.xib
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomView" owner:self options:nil];
yourView = (CustomView *)[nib objectAtIndex:0];
I also found this tutorial that also has a link to the projects files and it gives a better idea regarding to how to do this:
Creating Reusable UIViews
Here's a tutorial I wrote for creating a custom UIView with .xib, .h, .m files. I've added two sample projects showing Interface Builder and programmatic approaches.
https://github.com/PaulSolt/CompositeXib

Loaded nib but the 'view' outlet was not set

I added a new nib file to my project, and tried to load it.
However, when I click on the toolbar icon that is supposed to take me to the view that I created, I get an NSInternalInconsistencyException with the message:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: '-[UIViewController
_loadViewFromNibNamed:bundle:] loaded the "..." nib but the view outlet was not set.'
So I opened up my nib file, and I see for the view that there are no referencing outlets set. However, I try to click and drag the circle for "new referencing outlet" to File's Owner, but it won't let me...what do I need to do to get my view to display?
Here's what worked for me:
Open the XIB file causing problems
Click on file's owner icon on the left bar (top one, looks like a yellow outlined box)
If you don't see the right-hand sidebar, click on the third icon above "view" in your toolbar. This will show the right-hand sidebar
In the right-hand sidebar, click on the fourth tab--the one that looks a bit like a newspaper
Under "Custom Class" at the top, make sure Class is the name of the ViewController that should correspond to this view. If not, enter it
In the right-hand sidebar, click on the last tab--the one that looks like a circle with an arrow in it
You should see "outlets" with "view" under it. Drag the circle next to it over to the "view" icon on the left bar (bottom one, looks like a white square with a thick gray outline
Save the xib and re-run
This is Josh Justice proposal, but in a graphical way (pictures are mine):
Select File owner
On right hand side panel select custom class.
Enter the custom class name
On right hand side panel select oultets
Drag view outlet to view component
Finally the View Controller is instantiated with the rolling code:
PTFilterUserVC *aFilterUserVC = [[PTFilterUserVC alloc] initWithNibName:#"FilterVC" bundle:nil];
//OPTIONAL.This is how 'I' am interested in present the view controller.
[self.navigationController pushViewController:aFilterUserVC animated:YES];
I can generally fix it by remaking the connection between File's Owner and the view. Control-drag from the File's owner to your View (in IB) and select view from the pop-up menu.
The View Identity - Class Identity was not set. After setting it to the appropriate class, the issue was resolved.
Are you sure you have a UIView (or subclass) assigned to the "view" property of yourViewController?
Right click on "File Owner" in the left pane of the xib for yourViewController and verify that the "view" outlet is set.
If not, set it to a view!
this will definetly fix the Issue
For me all the things stated here https://stackoverflow.com/a/6395750/939501 were true but still it was throwing error, reason was I created a View class with name ABCView and then deleted it later I added a view controller as ABCViewController so somehow it was referring to old ABCView in new view controller, I had to delete the ABCViewController and add a new one with different name that solved my issue.
Thanks
I had the same issue with XCode 4.6.3. I had started out with a couple files named MySettingsView.h and .m but deleted them in favor of MySettingsViewController.h, but despite trying most of the hints mentioned here, it still kept erroring with,
2013-07-05 11:48:17.205 MyApp[39024:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason:
'-[UIViewController _loadViewFromNibNamed:bundle:] loaded the
"MySettingsView" nib but the view outlet was not set.'
It was evidently still "confused", trying to load MySettingsView.xib instead of MySettingsView Controller.xib. Maybe its "do what I mean" logic is too fancy.
So I worked around the problem by hardcoding the NIB/XIB name in MySettingsViewController.m:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:#"MySettingsViewController" bundle:nibBundleOrNil];
}
I ran into this problem in a slightly different way from the other answers here.
If I simply created a new xib file, added a UIViewController to it in Interface Builder, and set that UIViewController's custom class to my view controller, that resulted in the "view outlet was not set" crash. The other solutions here say to control-drag the view outlet to the View, but for me the view outlet was greyed out and I couldn't control-drag it.
I figured out that my mistake was in adding a UIViewController in Interface Builder. Instead, I had to add a UIView, and set the Custom Class of the File's Owner to my view controller. Then I could control-drag the view outlet of the File's Owner to my new view UIView and everything worked as it should.
To anyone that is using an xib method to create a UIView and having this problem, you will notice that you won't have the "view" outlet under the connections inspector menu. But if you set the File's Owners custom class to a UIViewController and then you will see the "view" outlet, which you can just CMND connect an outlet to the CustomView.
My issue with this was caused by having a duplicate nib in the class folder that did not have the view set. xcode seemed to be choosing one nib for a build and then the other the next time I built the project. Just deleted the other one. Looks good. Doh!
Just spent more than hour trying to find out why my view property is not set in my view controller upon initiating it from nib. Remember to call "[super initWithNibName...]" inside your view controller's initWithNibName.
I just fixed this in mine. Large project, two files. One was "ReallyLargeNameView" and another was "ReallyLargeNameViewController"
Based on the 2nd answer chosen above, I decided I should clean my build. Nada, but I was still suspect of XCode (as I have two identical classes, should abstract them but eh...) So one's working, one's not. File's owner names are so far as copy and pasted, outlets rehooked up, xCode rebooted, still nothing.
So I delete the similar named class (which is a view). Soon, new error "outlet inside not hooked up" literally was "webView not key value" blah... basically saying "Visual Studio's better". Anyway... I erase the smaller named file, and bam, it works.
XCode is confused by similar-named files. And the project is large enough to need rebooting a bit, that may be part of it.
Wish I had a more technical answer than "XCode is confused", but well, xCode gets confused a lot at this point. Unconfused it the same way I'd help a little kid. It works now, :) Should benefit others if the above doesn't fix anything.
Always remember to clean your builds (by deleting off the simulator too)
The previous answers almost solved the problem for me, but the last step was missing.
Create a xib and swift file with the same name.
Set the file owner to be the UIView subclass.
Drag an outlet from the View to the UIView subclass, name it "contentView"
Add this custom initializer so when the xib loads it attaches the contentView
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
Bundle(for: self.classForCoder).loadNibNamed("SampleView", owner: self, options: nil)
addSubview(contentView)
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
}
Now any #IBOutlets you add will be attached.
Cheers,
Richard
I also had the same problem and my issue was that i added an other Localisation (English) to the ViewControllers nib so my App with the Localisation German couldĀ“t find the nib with the Localisation English!! Hope this helps anybody!
I had face the same problem while accidentally deleted xib reference and added it again.I just fixed by making connection between Files owner and the view.Also make sure that your FilesOwner's custom class is your expected viewController.
For me, the problem was caused by calling initWithNibName:bundle:. I am using table view cells from a nib file to define entry forms that sit on tableViews. As I don't have a view, doesn't make sense to hook to one. Instead, if I call the initWithStyle: method instead, and from within there, I load the nib file, then things work as expected.
I had the same problem, but a slightly different solution was called for. The problem in this case was the class of the File Owner, rather than the class of the View. To set this, I had to click the "backwards play" icon in the lower left corner of the Interface Builder window, and options then appeared that isolated the characteristics of the File Owner, the First Responder, and the View. Clicking on the first one (a large transparent box), enabled me to then set its custom class as suggested above.
I had the same problem, but a different solution was called for. The problem in this case was the class of the File Owner was not connected to xib file.
I ran into something very similar tonight, with a Swift UIViewController subclass. In this case, none of the above fixes worked, but reordering my code a bit did. Net-net, having an extension to the subclass occur before the subclass's definition itself in the same file seems to confuse XCode, despite compiling fine; the fix was to place the extensions after the subclass's definition.
I've posted the details in an answer to this similar question.
In my case , the designated initializer - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil in ***ViewController class was implemented so even if when I call other initializer to initialize the object ,the designated initializer will be called .
So to resolve this problem checking wether the - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil is also a proper way.
My problem was in wrong classes. I used custom .xib for my custom view.
Correctly it has to be set like here:
View shouldn't have a class
Class which is used with the .xib is set in File's Owner tab
Outlets are connected to File's Owner and not to the View.
Just had the same error in my project, but different reason. In my case I had an IBOutlet setup with the name "View" in my custom UITableViewController class. I knew "view" was special because that is a member of the base class, but I didn't think View (different case) would also be a problem. I guess some areas of Cocoa are not case-sensitive, and probably loading a xib is one of those areas. So I just renamed it to DefaultView and all is good now.
select the files owner and goto open the identity inspecter give the class name to which it corresponds to. If none of the above methods works and still you can't see the view outlet then give new referencing outlet Connection to the File's Owner then you can able to see the view outlet. Click on the view Outlet to make a connection between the View Outlet and File's owner. Run the Application this works fine.
In my case, the view was not viewed in xib.
in xib the View was size = none (4th tab right hand). I set size to Freeform and reload xCode.
view was appealed and I set the proper link to View.
If you have tried everything and you still get this error, try re-creating the class file from scratch but remember to select the "Also create XIB file" check box. This will auto link up a few items that are not linked when creating these files separately. After this is created, you can likely cut and paste everything onto the new XIB and it should work fine.
I am finding this issue specifically with creating files separately in Swift.
for me it happened, when
I have a ViewController class ( .mm/h ) associated with the Nib file,
UIView from this ViewController has to be loaded on the another view as a subview,
we will call something like this
-(void)initCheckView{
CheckView *pCheckViewCtrl = [CheckView instance];
pCheckView = [pCheckViewCtrl view];
[[self view]addSubview:pCheckView];
[pCheckViewCtrl performCheck];
}
Where
+(CheckView *)instance{
static CheckView *pCheckView = nil;
static dispatch_once_t checkToken;
dispatch_once(&checkToken, ^{
pCheckView = [[CheckView alloc]initWithNibName:#"CheckView" bundle:nil];
if ( pCheckView){
[pCheckView initLocal];
**[pCheckView loadView];**
}
});
return pCheckView;
}
Here loadView was missing,,, adding this line resolved my problem.
I had the same problem, I figured out and it is because of i had ticked "Static cells" in the properties of Table View under Content option. Worked when it changed to "Dynamic Prototypes". Screenshot is below.
I had a similar problem with Xcode 9.3, and setting "Module" under the "File Owner's" attribute inspector to the project module fixed this for me.
Open your storyboard file where your viewController exists, or XIB related file with textEdit.app and check if the storyboard or XIB name is the same of your viewController, then change it, save and reload/restart Xcode.
If you're using a custom init method, check that you're returning something valid. I ran into a piece of code that crashed on something like this:
- (id)init {
self = [super init];
if (self) {
CustomController *controller = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass(className) owner:self options:nil];
} return self;
}
In another class, the controller was created like so:
CustomController *controller = [[CustomController alloc] init];
The problem is that in the init method, self hasn't changed and should look like this instead:
- (id)init {
self = [super init];
if (self) {
CustomController *controller = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass(className) owner:self options:nil];
[controller viewDidLoad];
self = controller;
} return self;
}

How to access IBOutlets declared in superclass?

I'm currently refactoring a couple of view controllers that share a few IBOutlets and IBAction methods. I moved the outlet declarations and the IBAction method into a superclass, cutting these out of the subclasses.
Now, when I open up Interface Builder, I find that I can't see the outlets or actions declared in the superclass. The connections still exist, as I'd wired them up before the refactoring, but they're grayed out. (It's important to note that the connections also WORK, as my action fires on a button press, and my outlets are modified properly.)
The question is, how can I get interface builder to recognize outlets from a superclass? Is this possible, and, if not, what do you all recommend?
(Just for fun, here's my superclass header file:)
#interface TFMainViewController : UIViewController {
UIImageView *logoImage, *thinkfunImage;
UIButton *buyFullButton;
}
#property (nonatomic, retain) IBOutlet UIImageView *logoImage, *thinkfunImage;
#property (nonatomic, retain) IBOutlet UIButton *buyFullButton;
-(IBAction) buyFullVersion;
#end
EDIT: in case anyone's wondering, I'm using Xcode and IB 3.2.5, with the iOS 4.2 SDK.
I didn't realize it was even possible to connect to superclasses in interface builder until about an hour ago. Since this was the only question I could find regarding how to do this, I'll add my answer, even though this question is old. My answer is with regard to Xcode 4, not Xcode 3.
As far as I can tell, you can't connect to outlets in a superclass using the assistant editor, but you can do it by clicking on "File's Owner" in IB. That should show all the outlets in Utilities->Connections Inspector. You can then Ctrl+Click on the outlet in the inspector (click on the '+' sign), and drag it over to your view in IB.
The solution for the problem with the IBOutlet .. is to change the class type to the Base Class in the identity inspector
connect using Control + drag and drop and
change it back to the child class
This works for me
BTW: i used Xcode 6
IB should be able to see outlets from superclasses, I have done this a number of times with no issues. Are you sure you are importing the superclass correctly (using #import instead of #class)? IB needs some way to track back to the superclass.
Switching between the super and subclass in the identity inspector allows you to connect your outlets across the classes. The only issue I found is when you attempt to do this with a UITableViewCell and its subclass. I wanted to re-assign the default textLabel and detailTextLabel instances to labels I create in Interface Builder. The workaround is to create substitute labels and then override the getters to point to these instead.
I'm pretty sure that IB only looks at the actual class you're using to find outlets, and not at superclasses. I think that the easiest solution would be to leave the instance variable declarations in the superclass, but duplicate the #property lines in each subclass.
I'm doing this in XCode 3.2.6. I started with outlets connected to a class, and then made a subclass with additional outlets. When I changed the File's Owner class to the subclass, IB showed the superclass outlets as greyed out. I switched File's Owner to the superclass, then back to the subclass and now all outlets are showing not greyed out.
The simplest way: create interface and implementation files for your subclass(es)!
Perfect example: Juggleware's awesome ShadowButton Subclass of UIButton.
Make sure to create the .h & .m files in your project.
NOTE: There is no need to #import the header files at all since this is simply a class instance of UIButton.
In Interface Builder:
Select the element you which to connect.
Go to Utilities -> Identity Inspector
Change the Class to your subclass (or superclass). NOTE: You might have to type in your subclass name and hit ENTER.
You're done!
Even if you have declared a basic class (UIButton) as IBOutlet in your header file like so...
// YourViewController.h
#interface YourViewController : UIViewController {
IBOutlet UIButton *mybutton;
}
...the class you've set in Interface Builder (ShadowButton) will overwrite it since it's in the view layer.
The best part about this approach is that your code doesn't have any messy dependency issues.
On the project I am currently working, we have a BaseViewController with a UIScrollView as IBOutlet and handles keyboard appearance/disappearance events and slides the content accordingly. At first, I could not connect to that IBOutlet, than solved the problem like this, which is similar to Sosily's answer:
BaseViewController has an IBOutlet, called contentScrollView. I can see 5 previously connected outlets, which are UIScrollViews on other UIViewControllers, created by people who previously worked on the project
I tried to connect my UIScrollView as the contentScrollView. Although my UIViewController is a subclass of BaseViewController, I cannot connect it.
I tried to connect already connected UIScrollViews as the contentScrollView. Although all UIViewControllers are subclasses of BaseViewController, I cannot connect them again, as well. So, I started to look for a trick.
I have created the same contentScrollView IBOutlet on my own UIViewController, connected the scrollView to my own contentScrollView outlet and removed the one that I have just created.
Now the scrollView is connected as contentScrollView to File's Owner, but the only contentScrollView belongs to the BaseViewController. Tested and verified that keyboard events are handled correctly.
I ran into a similar problem with a superclass, but it was due to a bug in Xcode (8.2) where Interface Builder doesn't show outlets in the Connection Inspector if those outlets have been declared with a _Nullable type annotation for Swift compatibility.
Using nullable inside #property's parentheses appears to work around the problem.
This Xcode bug seems to affect outlets in any class (ie. not just superclasses).
I had the same problem, and it turns out it was because in the superclass I had the IBOutlets declared as "_Nullable".
Example:
#property (nonatomic, strong) IBOutlet UITableView *_Nullable mySuperTableView;
When I removed the _Nullable, suddenly the IBOutlets reappeared in IB and all was good again.
(I had only set them to _Nullable because Xcode was complaining "pointer is missing a nullability type specifier"... (don't know why). )

Resources