1

I am not exactly sure the best practice of doing this, so I thought I'd ask.

Here's the program's objective:

  • A custom navigation controller created via a root UIViewController that does not actually subclass UINavigationController(To easily manipulate the design)
  • Nested view controllers for different screens (manipulated by the main view controller)
  • Each nested view controller has its own nib file

Currently, I have it working, however each nested view controller is not a view controller but a subclassed UIView. I feel like this is bad practice because I am using these UIViews in a view controller way but without the functions of a view controller (ie. viewDidLoad). Also, these UIViews are taking on the usual delegate methods of a UIViewController (which really sets off red flags).

Is this actually bad practice?

Things I am afraid of when trying to switch to UIViewControllers are that I would still have to make a subclass of UIView to identify which view to point to when I load the nib via:

NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil];

for (id object in bundle) {
    if ([object isKindOfClass:[SubclassedUIView class]])
        currentScreenViewController = (SubclassedUIView *)object;
}

I haven't checked yet, but I assume I have to do "SubclassedUIView" rather than just UIView in that statement because there are other UIView objects in the bundle. But then again, that situation may be better off than the current one.

A different solution may be to make MainViewController a delegate for all of the UIViews that require a delegate and create categories of the MainViewController containing the delegate methods for each nested nib.

Any idea here?

AndrewKS
  • 3,603
  • 2
  • 24
  • 33

2 Answers2

3

Create a UIViewController subclass for each SubclassedUIView type, ticking the option to create a XIB file for the interface, and move all of the code over to that, pointing it to self.view. Then open up Interface Builder with the .xib for that view controller and configure the visual appearance of the UIView as much as you like. To manipulate visual elements from the main view controller you will have to either assign "Tag" numbers to each element or create a whole bunch of IBOutlet instance variables and hook them up to your elements in IB. The way you present view controllers properly using a UINavigationController is:

/* at the top of your main view controller */
#import "SubclassedUIViewController.h"

/* when navigating to the next view */
SubclassedUIViewController *newController = [[SubclassedUIViewController alloc] initWithNibName:@"SubclassedUIViewController" bundle:nil];
[(UILabel *)[newController.view viewWithTag:6] setText:@"Text"]; // example of accessing elements using tags
[newController.textLabel setText:@"Text 2"]; // example of accessing elements using IBOutlet connections
[self.navigationController pushViewController:newController animated:YES];
[newController release];

Interface Builder also allows you to add the navigation controller to your main view controller .xib file and provide the back button text, main title, etc. When you implement your subclassed view controllers, override initWithNibName:bundle: and set self.navigationItem.title and any other properties of self.navigationItem you want.

EDIT: Did you mean you have to be able to manipulate specific properties of some of the subclassed views while in other ones? As in, you require access to all of them all the time? If this is the case then make connections to your subclassed views upon loading the main view controller, that is:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.subclassedController1 = [[SubclassedUIViewController1 alloc] initWithNibName:@"SubclassedUIViewController1" bundle:nil];
    // self.subclassedController2 = ... etc
}

/* in your loading next view code you can skip the alloc/init line */
[self.navigationController presentViewController:subclassedController2 animated:YES];

And then in your subclassed controllers you can get to the main controller in a few ways:

  1. A call to self.parentViewController
  2. A call to [(MyCustomAppDelegateClass *)[[NSApplication sharedApplication] delegate] rootView] or similar (basically, the reference your application delegate holds to the main view of the application).
  3. By adding an @property (assign) property and ivar to the subclassed controller pointing to the main view controller. You can assign this on loading your main view controller with subclassedController1.mainViewController = self.

Helpful docs:

  1. View Controller Programming Guide for iOS: Navigation Controllers
  2. Xcode Quick Start Guide (updated for Xcode 4)
  • Sorry - I don't want to subclass UINavigationController however, because it's to restrictive. Edited my question a bit to reflect that that is made clear. – AndrewKS Mar 25 '11 at 15:13
  • All of what I wrote above can be handled by the normal, non-subclassed `UINavigationController`. The subclasses I talk about are what you push and pop with your default navigation controller. Even the root view controller is just a subclassed `UIViewController`. The navigation controller itself is actually defined inside the Interface Builder interface of your main window, as a subview of the main view of your root view controller. –  Mar 28 '11 at 00:13
  • I want to do the same thing but assumed UINavigationController is not the way to go because you can't specify how the next controller transitions. for example, push/pop controls their animation from left-right, but I want more control over that. I made a prototype that works, but I think it has problems with multi-threading when integrated into my codebase because my prototype project doesn't work anymore. I suspect there's something sophisticated going on in UINavigationController that UIViewController somehow can't. I don't know. – horseshoe7 Nov 24 '11 at 22:51
  • I found this link that does a good explanation of your problem and a potential solution: [Abusing UIViewControllers](http://blog.carbonfive.com/2011/03/09/abusing-uiviewcontrollers/) – horseshoe7 Nov 24 '11 at 23:18
0

Apparently, what I was doing was sort of OK according to How to add an UIViewController's view as subview.

Community
  • 1
  • 1
AndrewKS
  • 3,603
  • 2
  • 24
  • 33
  • you can also check solution from another post http://stackoverflow.com/questions/17499391/ios-nested-view-controllers-view-inside-uiviewcontrollers-view – Mobile Developer Jul 23 '15 at 10:13