Accessing Views created in Interface Builder - objective-c

I've created a ChildViewController class, and then a nib that uses that class.
Then I created a BaseView, that includes some buttons, and some text that I'll be changing programmatically.
Then I created two more views (Boy and Girl), that I want to be able to lay behind the baseview so that the background color is different along with some graphics in an ImageView. I've named the views that I created in IB 'Boy' and 'Girl'...
But when I go back to my code where I'm calling ChildViewController, I'm not sure how to access the views I created so I can call insertSubView. Do I need to instantiate them in code? (in ViewDidLoad perhaps?) Does the nib create the instances when it loads?
I'm confused about how to handle multiple views for a single ViewController
edit =================
#Pablo Santa Cruz
Your answer assumes that i have two nibs and two view controllers (one for each view). I want to know if I can use one nib and one controller, and load in UIViews. It seems silly to create another nib and controller, when all want to do is change the background color and some graphics. Can't I programatically load in UIViews into a UIViewController?

Add IBOutlets in your App Controller class in Xcode then link them in IB (ctrl-click or right-click) from the connections tab in the Inspector to the object.
Then you will be able to send method calls to the objects.
The code in Xcode should look like this:
#interface AppController : NSObject
{
IBOutlet Girl girlIvarName1;
IBOutlet Boy boyIvarName2;
}
#end

You can access a UIView programatically by assigning a value to its tag property, which can be set in IB on the first tab of the inspector (Command 1)
The tag value defaults to zero, so if you want to access it specifically, make it non zero and unique. e.g. 100, which I will use in the example code below
Once the tag is set you can access the view using the following code in your UIViewController that was initWithNibName for the NIB containing the tagged view
UIView *aView = [self.view viewWithTag:100];

You can get instances for your IBuilder views with this piece of code:
boyViewController = [[BoyViewController alloc] initWithNibName:#"BoyViewController" bundle:nil];
girlViewController = [[GirlViewController alloc] initWithNibName:#"GirlViewController" bundle:nil];
Assuming your NIB file names are BoyViewController and GirlViewController. With those instances, you can do whatever you need to. I.E., adding them to a parent view (with addSubView message on the parent).

Related

Change a UIViewController to a UITableViewController inside a storyboard?

I've made a view in my storyboard which I've now decided I'd rather display its data via static table cells.
I can't use static table views in a UIViewController (Static table views are only valid when embedded in UITableViewController instances). So, I need to convert my existing UIViewController to a UITableViewController somehow. I've changed the .h file's parent, but that hasn't done it.
Is there another way to get this going? I'd really rather not have to make a new VC in the storyboard and move everything over, it's a big hassle.
I'll add to this, since the question is about how to change a UIViewController into a UITableViewController, and given that this question is over a year old and the original answer, while valid and may or may not have been the only solution at the time, doesn't actually answer the question and is not the only solution.
It IS possible to do this, you just have to set up the table view delegate and datasource outlets in IB, and manually edit the storyboard XML, which sounds scary but is actually very easy.
First, change your class's parent to be a UITableViewController. UITableViewController already adopts the UITableViewDatasource and UITableViewDelegate protocols, so if your class does too you can remove them:
#implementation MyTableViewController : UITableViewController
...
#end
Next, create new referencing outlets on your UITableView for its dataSource and delegate. The easiest way to do this is to control-drag from the UITableView to itself. The popup will give you the dataSource and delegate options.
Lastly, you need to change the storyboard XML. The storyboard file can get pretty big pretty fast. The easiest way to find the scene you are looking for is by setting Storyboard Identifier in the Identity Inspector. To view the XML directly, right click on the storyboard file in the project navigator and select "Open As -> Source Code". Now just search for whatever you set the reuse identifier to earlier. You'll see something similar to this:
<!-- My Table View Controller -->
<scene sceneID="EuE-XX-cCb">
<objects>
<viewController storyboardIdentifier="MY_TABLE_VIEW_IDENTIFIER" ... >
// Lots of other stuff
</viewController>
</objects>
</scene>
All you need to do is change the opening and closing view controller tags
<viewController>
</viewController>
to be tableViewController instead
<tableViewController>
</tableViewController>
That's it! No need to create a new UITableViewController scene or embed a UITableViewController in a container view.
EDIT:
I should also add that the UITableView MUST be the root view. It cannot be embedded inside another UIView.
If you want your static cell table view not to take up the entire screen, then using a container view is the easiest way to go. Start with a regular UIViewController and drag a container view (next to normal UIView in the object list) into its view. Resize it however you want -- the storyboard will automatically provide a view controller connected to this container view with an embed segue. Delete that controller, drag out a table view controller and right-drag from the container view to this table view controller to make a new embed segue. This table view controller can be accessed from the UIViewController with its childViewControllers property (and conversely, you can access the UIViewController from the table view controller with parentViewController if you need to).
What I did, is creating a UITableViewController in IB, open the Storyboard with a text editor, and copy all the nodes inside from the UIViewController to the UITableViewController.
I think that with this way there's less risk of deleting something important.
Before copying the sections objects, make sure that both tableviews (UIViewController and UITableViewController) have the same properties set like: static or dynamic cells, style (plain or grouped), etc.

iOS subview widget hooked up to multiple controllers

So, I want to create a reusable widget as a xib and subview that can appear on a set amount of specific screens. This widget will have three buttons, each with an Action.
I want to be able to handle these actions on multiple viewcontrollers.
So say ViewControllerA, ViewControllerD, and ViewControllerF can handle the three button events, each in their own way.
I've created the nib file. How do I import it into the specific viewcontrollers, and then how do I wire up those events?
EDIT: I know that I could potentially get outlets set up via a viewcontroller, but Apple states that UIViewController is for full-screen views only, and my widget is only taking up a small portion of the screen.
You have done correctly. And one thing is, In iOS it's not widget.It's a UIView.
(Sorry there may be any typo in my code.I have written myself in StackOverflow)
Follow Below Steps to finish it..
1) After you have created the xib for the view, then you need to have a UIView subclass files.. For example your xib name likes this CustomView.xib means then create a files like this CustomView.m and CustomView.h
2) In your CustomView.xib , You need to set the fileOwner as your CustomView.h.
3) In your CustomView.m file, there will be a method like initWithFrame: In that method you need to load your xib file like this
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomView" owner:self options:0];
UIView *currentView = [topLevelObjects objectAtIndex:0];
[self addSubView:currentView];
4) Almost over. In any of your view controller, you can use this xib like
CustomView *newSubView = [[CustomView alloc]initWithFrame:CGRectMake(0,0,55,67)];
[self.view addSubView:newSubView];
That's it.. Go on..
You have created a nib file but make sure that you have also created the .h and .m file that will be the controller for that nib file. You will have to look up how to implement delegate methods which your other view controllers can capture and act on in their own way. Here is a great tutorial to get you started on making custom classes with custom delegates: Link

Is it a good practice to subclass a UIViewController's subclass?

Say you have a 2 subclass of tableView controller.
They both have the same header and footer view on top of the bottom of the header. They both implement pull to refresh.
They both have some common features.
The only different is one is for displaying the whole businesses, the other is for displaying only businesses you bookmark.
It looks like they both need to have the same parent class and the different is resolved on the child class. The differences are minor anyway.
I suppose the parent has it's own XIB, the children has it's own XIB.
Hmm... How would that work out? With the exception of container UIViewController, each controller should view a fullview of content. So which view should we display? The child or the superClass? Should child view add it's superclass subview?
Anyone have ever tried that?
Any code sample on the web that use this approach?
It sounds like, based on the business logic you explain, that everything is in common, except the list of data you're presenting. You could expose a property on your UITableViewController subclass to set the business objects that your tableview presents:
#interface JTBusinessesTableViewController : UITableViewController
#property (nonatomic, strong) NSArray *businesses;
#end
The code that instantiates this class would set the business objects:
JTBusinessesTableViewController *businessListings; //Instantiate from XIB or Storyboard
businessListings.businesses = [self bookmarkedBusinesses];
[self.navigationController pushViewController:businessListings animated:YES]
The code for displaying all businesses isn't going to be much different:
JTBusinessesTableViewController *businessListings; //Instantiate from XIB or Storyboard
businessListings.businesses = [self allBusinesses]; // Here we assign all of them
[self.navigationController pushViewController:businessListings animated:YES]
You're just selectively giving this view controller, the business objects to display.

iPhone: Accessing view objects from a ViewController in Code

Let's say I have a ViewController that needs access to a view. In the class file of the ViewController I am doing
IBOutlet ViewA *someview;
And in Interface Builder, I drag and drop a UIView in my document and set the class to ViewA.
I am missing how "stuff" is instantiated when you connect through IB. Is ViewA automatically allocated when the .xib files are unarchived? What if I don't want to use IB?
If you don't want to use IB, instead of putting that IBOutlet there, you just eliminate it, leaving just
ViewA *someview;
and then somewhere in your code, when you need the view, you do a
someView = [[UIView alloc] initWithFrame: rect];
I prefer IB, others prefer programmatically creating views. I like how I can position all the views subViews, including UIButtons, UILabels, UITableViews, other UIViews, etc. without having to use coordinates to do so. YMMV.
As to when things get instantiated, when using a XIB, your app will probably lazily load the view controller, and once it is loaded, it will load your view. What actually loads your view, is when you first access the variable someView. While there is an outlet connection, the view and its subViews are not loaded till you access someView, in any manner, for example if you just do a:
if (someview) {
// the view is loaded now
}

Is it possible to initialize a UINavigationController subclass from a NIB?

I have a UITabBarController based application. The tabs will be created from database entries, so I don't know them in advance. I'd like to programmatically initialize a UINavigationController subclass (I have a few different kinds) for each tab.
Ideally, I would really like to draw the whole UINavigationController subclass + it's subview using Interface Builder, just like you can do when you add define the view for each tab in IB (that's when you know what the tabs will be in advance). I've tried setting the "Class identity" to my UINavigationController subclass name, then add a UINavigationController inside it, but obviously it didn't inject the instance at the "File's owner" level...
Thanks
I've ended up not subclassing UINavigationController, it appears it isn't what's recommended. I quickly realized that there wasn't a whole lot of benefit from designing the UINavigationController's from within IB. Instead, I subclassed UIViewController, wrote the few lines of init for theUINavigationBar (custom buttons, custom middle image) in my viewDidLoad. It's just better to simply wrap the subclass with [[UINavigationController alloc] initWithRootController: subclass]; when I programmatically fill my tabs. Subclassing UINavigationControllerdirectly prevented me from properly using the navigationItem property of my inject view.