UIView in nib not connecting to IBOutlets - ios

I am adding on screen a UIView in this way:
ViewController2 *detailViewController = [[ViewController2 alloc] initWithNibName:#"MJDetailViewController" bundle:nil];
[self presentPopupViewController:detailViewController animationType:MJPopupViewAnimationFade];
since MJDetailViewController is a nib and holds a UIView, I have created a custom class of UIView and selected it as class for the view in the inspector. When the window is loaded, the UIButtons do actions in the class that has been created, but the IBOutlets don't work. Even if I decided to add a UIButton programmably, it doesn't appear on screen. Why is this?
I thought of changing the UIView to a UIViewController, but it won't work because you can't present it with an animation.

I suspect you haven't set up the nib objects correctly.
In addition to setting the class of your UIView subclass you need to configure the 'File's Owner' and connect the views to it. You do this by selecting the file owner and setting its' class (this is done the same as setting the view's class). In your case the class of the file owner should be ViewController2.
Hopefully this screenshot explains this better:
Also you can simplify things a bit by using UIViewController nib naming conventions. If you give your nib the same file name as the view controller then you can specify nil as the nibName:. For example, if you name your nib ViewController2.xib then you can do this:
ViewController2 *detailViewController = [[ViewController2 alloc] initWithNibName:nil bundle:nil];
This approach is preferable as it means that the nib filename becomes an implementation details which calling code does not need to know about.

Related

Xcode 6 subclasses

I want to put a view controller inside a scroll view.
I think I can do it with something like:
MyViewController *vc = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
[scrollView addSubview:vc];
What I don't understand is how to specify my nib name correctly, because I have an interface built which I want to use but it is one of multiple views appearing in my main storyboard.
You cannot add a viewController as a subview. You can add a childViewController and the viewController's view as a subview. But you should probably read up more on how Objective-C and iOS works.

Passing Data to subView Using same .h and .m class in iOS

I have aded a new View in my app, its just a .xib file
On button click i am calling this new view... AS
UIViewController *newView = [[UIViewController alloc] initWithNibName:#"Welcome" bundle: [NSBundle mainBundle]];
[self.view addSubview:newView.view];
It call successfully the new view.
I have set some labels and button newView that are shown on button click.
now the problem is this,
1- i have to send or pass some data to newView from main and also
2- when i connect a UILabel using CONTROL Drag in interface builder on selecting File's Owner Of newView with desired Label it gives me error on button click
'[<UIViewController 0x89d05b0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key Users.'
'User' is the UILabel type variable In my .h file that is declared as
#property(nonatomic ,retain) IBOutlet UILabel *Users;
any suggestion or help would be appriciated
You're creating a UIViewController instead of your custom UIViewController subclass. What you should be using is:
MyViewController* vc = [[MyViewController alloc] initWithNibFile:...]
Also note that if you're using child view controllers, you should be calling addChildViewController with the newly created view controller so that the UIViewController methods are properly propagated to the child view controller.
One last note, none of this will work reliably before iOS 5, as up to that point child view controllers were strongly advised against.
It also sounds like you're not using a subclass for the child view controller, if you add properties or actions, you have to use a subclass.

Using custom View with Storyboard without adding it twice

I'm using Storyboard and trying to reuse a View for different ViewControllers.
For that, I created a custom .xib (MyCustomView.xib) and class (MyCustomView) as suggested pretty much everywhere.
In my Storyboard I set the custom view to be of type MyCustomView.
In MyCustomView.xib, set First Responder to MyCustomView.
In MyCustomView.m, I added the following method:
-(id)initWithCoder:(NSCoder *)aDecoder{
if ((self = [super initWithCoder:aDecoder])){
UIView *myCustomView = [[[NSBundle mainBundle] loadNibNamed:#"MyCustomView" owner:self options:nil] objectAtIndex:0];
[self addSubview: myCustomView];
}
return self;
}
Problem is, [self addSubview: myCustomView] adds a new MyCustomView to existing MyCustomView, so the view is added twice.
How can I get rid of one of the two?
EDIT
My question is not really clear, so I thought some screen caps would help.
Here is my Storyboard with a custom view. Custom class is set to MyCustomView.
(I also added a grey background and a label for testing purpose only)
Now, in MyCustomView.xib, I set File's owner to be of Class MyCustomView:
And add outlets for title Label and imageView:
With the initWithCoder method as written above, this works fine, except when I debug I can see this:
So self is of course of type MyCustomView, as chosen in the Storyboard, but it contains 2 subviews :
First is the test label from my storyboard
Second is the view from MyCustomView.xib, itself containing a Label and image view. That's this view I want to get rid of.
What is self ?
Here, it is the MyCustomView you just instantiated. So, you're adding a new UIView (not MyCustomView) to your new MyCustomView instance created by the initWithCoder method.
initWithCoder is the method called when loading your storyboard view.
If you want to instantiate a new MyCustomView in your MyCustomViewController you have to call
MyCustomView *newInstance = [[MyCustomView alloc] init];
[self addSubview:newInstance];
Where self is the instance of MyCustomViewController in your storyboard.
EDIT
OK, I understand better your question.
If you want to load the MyCustomView nib file, you don't need to create a class for it (except if you have specific variables you want to access in it.
Just do what you're doing here, but in the view controller, which will be the self. :)
You might want to have a look at : How to load a UIView using a nib file created with Interface Builder
EDIT 2
Ok, I think I get it :
delete the MyCustomView in your Storyboard.
create a class MyView or whatever which you attach to the view named "View" in your Storyboard.
in the init method of your class you instantiate your MyCustomView nib
add the resulting UIView to the views stack like you did it.
self will be MyView (present in the Storyboard), MyCustomView won't appear in the storyboard but created programmatically in the init method of MyView.h
You will have to add constraints programmatically. Here is a post that can be helpful: Adding View Programatically With Auto Layout Gives 'NSGenericException', reason: 'Unable to install constraint on view

iOS How can I access UIView property from UIViewController

Can someone Please walk me through the steps because I feel a little stuck and lost
Previous question : iOS - set UIButton target and action from its super class
Now I'm trying to get a more general idea - I'm very new to this
Help is very appreciated
If you are looking to access the UIView of an associated UIViewController from inside the view controller itself, you simply use self.view. To access the same UIView from outside of the UIViewController class you would use the instance name of the class plus the .view property. For example:
//SomeClass.m
- (void)accessVCView
{
//With a Nib File:
MyUIViewController *aVCObject = [[MyUIViewController alloc] initWithNibName:#"MyNib" bundle:nil];
//Or with a Storyboard:
MyUIViewController *aVCObject = [[UIStoryboard storyboardWithName:#"myStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"MyViewController"];
UIView *myUIViewControllerView = aVCObject.view;
}

UIViewControllerHierarchyInconsistency when trying to present a modal view controller

Trying to present a modal view controller with the following code
MapViewController *mapView = [[MapViewController alloc] initWithNibName:#"MapViewController" bundle:nil];
mapView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self.navigationController presentModalViewController:mapView animated:YES];
[mapView release];
Keep getting the following error..
'UIViewControllerHierarchyInconsistency', reason: 'A view can only be associated with at most one view controller at a time! View <UIView: 0x1ed815a0; frame = (0 20; 320 460); autoresize = W+H; layer = <CALayer: 0x1ed81600>> is associated with <UIViewController: 0x1ed835a0>. Clear this association before associating this view with <MapViewController: 0x1dd947c0>.'
This is an old project that I havent touched in months, wonder what could cause such an error?
This happened to me already twice in the newest Xcode release.
In both cases I needed to make changes to the UIViewController's XIB file (In you case it would be MapViewController.xib:
BEFORE:
Move main View out of View Controller's children:
Remove View Controller from the XIB (it is not necessary since File's Owner should be of its Class already):
AFTER:
I had this problem when running Apple's example audio app MixerHost on the iOS 6 simulator.
The equivalent of the above fix, namely to edit the supplied MixerHostViewController.xib by dragging the View object to the top level, and discarding the now-empty ViewController that used to contain it, worked perfectly (though not before I'd spent hours working out what the underlying problem was, so I'm feeling done-over by Apple at the moment - seems they tightened something up but didn't bother to check if it broke their sample apps).
I had this problem when my Nib had a UIViewController in the file at top level. So loading from Nib created that UIViewController, then I tried to use it from my class, which was in the position of MapViewController in your code.
In my case the solution was simply to remove the UIViewController from my Nib file.
You should do it like this..
MapViewController *mapView = [[MapViewController alloc] initWithNibName:#"MapViewController" bundle:nil];
UINavigationController *navCntrlr = [[UINavigationController alloc] initWithRootViewController:mapView];
mapView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
//hide navigation bar if needed
[self.navigationController presentModalViewController:navCntrlr animated:YES];
[mapView release];
Maybe in some cases it is better to take another approach and not delete the UIViewController from the NIB, because, for one thing, by removing the view controller from the NIB's hierarchy, you lose the Auto Layout margins.
Why not just leave the UIViewController in your nib (.xib) and create an outlet for it in the file owner class? Then, rather than instantiate the view controller directly in you code, load the nib with the UINib class, and, at the optimal time (from the memory/resource usage standpoint), invoke the nib instance's instantiateWithOwner() method to unarchive NIB and connect the nib objects to the owner class's outlets.
#IBOutlet var myViewController: myViewController?
var nib : UINib?
nib = UINib(nibName: "TheNib", bundle: nil)
if (nib == nil) {
println("could not load nib: TheNib.xib")
}
nib!.instantiateWithOwner(self, options: nil)

Resources