Currently, I have a SplitViewController setup. Wherein the MasterViewController has a bar button, when pressed, a UITableViewController popovers.
I'm want to connect the delegate in UITableViewController to MasterViewController. Based on tutorials, most people do this in app delegate.
Here's my code in app delegate. I haven't added the TableViewController class yet.
UISplitViewController *splitViewController = (UISplitViewController *) self.window.rootViewController;
splitViewController.delegate = [splitViewController.viewControllers lastObject];
DetailViewController *detailViewController =(DetailViewController *) [splitViewController.viewControllers lastObject];
MasterViewController *masterViewController = (MasterViewController *) [[splitViewController.viewControllers objectAtIndex:0] topViewController];
masterViewController.delegate = detailViewController;
detailViewController.delegate = masterViewController;
Related
I'm working on a catalog application for iPad/iPhone devices. I'm, using the master view template from XCode to have a base, in the root or master navigation controller I'm showing the list of the products and now I'm trying to add a tab controller to the detail view because each product have 3 different sections, one with some details, other with a specifications table and other with some pictures or images of the product.
I'm doing this programmatically, this is my code of AppDelegate.h
#import <UIKit/UIKit.h>
#import "MVADetailVwCtrl.h"
#import "MVATableVwCtrl.h"
#import "MVAModelVwCtrl.h"
#interface MVAAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UITabBarController *rootTabBarCtrl;
#property (strong, nonatomic) MVADetailVwCtrl *detailVwCtrl;
#property (strong, nonatomic) MVATableVwCtrl *tableVwCtrl;
#property (strong, nonatomic) MVAModelVwCtrl *modelVwCtrl;
#property (strong, nonatomic) NSArray* viewControllers;
#end
And this is the code on AppDelegate.m
#import "MVAAppDelegate.h"
#implementation MVAAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.detailVwCtrl = [[MVADetailVwCtrl alloc] init];
// self.newMoveVwCtrl.title = #"Product details";
UINavigationController *detailNavCtrl = [[UINavigationController alloc] initWithRootViewController:self.detailVwCtrl];
self.tableVwCtrl = [[MVATableVwCtrl alloc] init];
// self.myAccountsVwCtrl.title = #"Table";
UINavigationController *tableNavCtrl = [[UINavigationController alloc] initWithRootViewController:self.tableVwCtrl];
self.modelVwCtrl = [[MVAModelVwCtrl alloc] init];
// self.settingsVwCtrl.title = #"Pictures";
UINavigationController *modelNavCtrl = [[UINavigationController alloc] initWithRootViewController:self.modelVwCtrl];
self.viewControllers = [NSArray arrayWithObjects:
detailNavCtrl,
tableNavCtrl,
modelNavCtrl,
nil];
self.rootTabBarCtrl = [[UITabBarController alloc] init];
self.rootTabBarCtrl.viewControllers = self.viewControllers;
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
splitViewController.delegate = (id)navigationController.topViewController;
}
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
splitViewController.viewControllers = [NSArray arrayWithObjects: self.rootTabBarCtrl, [splitViewController.viewControllers lastObject], nil];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
[[UINavigationBar appearance] setTitleTextAttributes:#{NSForegroundColorAttributeName : [UIColor whiteColor]}];
[[UINavigationBar appearance] setBarTintColor:UIColorFromHex(0x009B3E)];
return YES;
}
I'm creating each tab and each navigation controller of each tab and storing all of them in an array, and then I'm retrieving the view controllers of the split view to change them with the new ones but I don't know if this is the best approaching.
Maybe there is a best method editing the storyboard, and I would like to keep the compatibility of the application with iPad and iPhone devices.
Could you help me please? Thanks in advance.
The code you posted won't run on iPhone since UISplitViewController is only supported on iPad.
Have you considered to use Storyboards instead of doing this programatically? I think in your case this could make things a lot easier. In this Stanford course the teacher explains how to make an iPhone app using storyboard universal and he also uses a split view controller.
Just switch the order of the view controllers in your split view, which will switch detail and master view.
splitViewController.viewControllers = [NSArray arrayWithObjects: [splitViewController.viewControllers firstObject], self.rootTabBarCtrl, nil];`
I've created a new application view based.
Here some the main code:
// AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
UINavigationController *navigationController;
MIAPreferences *preferences;
}
#property (strong, nonatomic) UINavigationController *navigationController;
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) MIAPreferences *preferences;
// AppDelegate.m
#implementation AppDelegate
#synthesize window = _window;
#synthesize navigationController;
#synthesize preferences;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
// Override point for customization after application launch.
UIViewController *rootController = [[HomeViewController alloc] initWithNibName:nil bundle:nil];
navigationController = [[UINavigationController alloc]
initWithRootViewController:rootController];
navigationController.navigationBar.hidden = YES;
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
_window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
// HomeViewController.m
-(IBAction)openLogin
{
LoginViewController *view = [[LoginViewController alloc] initWithNibName:nil bundle:nil];
// 1
[self.navigationController presentViewController:view animated:YES completion:nil];
// 2
[self.navigationController pushViewController:view animated:YES];
// 3
[self presentViewController:view animated:YES completion:nil];
}
All 3 options returns a EXC_BAD_ACCESS (code=2, address=....)
Can you please help me understand how to solve this?
UPDATE
The problem was due to a UIButton apparence set up during AddDelegate loading....but the first button was in the UIView I was going to load... that's why it crashed -.-"
It could either mean: (1) The pointer used to point to memory that was ok, but its chunk was deallocated or (2) The pointer is corrupt. You can try to use zombie mode, if you aren't already, to get more information. In XCode press the Command, option, and I keys and a screen should pop up. Selected the Run option in the left hand side, then Diagnostics, and under memory management enable zombie objects should be checked.
Check the value of view after initWithNibName:. init'ing with a nil nib name looks wrong to me, and you may be trying to push a nil view controller onto your navigation stack.
is it possible to access a ViewController's methods from the appDelegate, like it is possible inverse with the following code:?
AppDelegate *ad = (AppDelegate *) [[UIApplication sharedApplication] delegate];
When I try
ViewController *vc = (ViewController *) [[UIApplication sharedApplication] delegate];
I get an error...
Thanks!
In your AppDelegate, assuming viewController is your rootViewController, you can get a list of all view controllers on the stack by with:
NSLog(#"List of current active view controllers:%#", self.viewController.navController.viewControllers);
To access a specific view controller in the viewControllers:
[[self.viewController.navController.viewControllers objectAtIndex:i] someMethodOfThatViewController];
ViewController *vc = (ViewController *)[UIApplication sharedApplication].keyWindow.rootViewController;
or if your delegate have properties
YourAppDelegate *ad = (YourAppDelegate*)[UIApplication sharedApplication].delegate;
ViewController *vc = ad.yourViewControllerProperty;
Did you notice that UINavigationBar is not set anymore when creating a UITableView, even after giving it a title or a button?
Now i'm going mad on how to put a navigation bar over my UITableView. It seems really impossible. I tried to add to my tableView a subview with the Navigation Bar, but seems worthless, because when I scroll down, the navigation bar scrolls down as wellm and it shouldn't.
Any ideas on how to implement it?
EDIT
Well, as always I went on File -> New -> File.. -> UITableView. Then i set a bit of code and when I wrote
self.navigationItem.title = #"MyTitle";
self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
and tried to test on Simulator, no Navigation Bar appeared.
My init code:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = #"TabTitle";
self.tabBarItem.image = [UIImage imageNamed:#"img.png"];
self.view.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
}
return self;
}
I can't explain why it doesn't appear anymore. I also tried to create a new project and import my classes from a project where the navigation bar appeared, but same result there too.
EDIT2*
The app is a tabBased application.
Here is the code took from the App delegate used to set up the tabBar.
UIViewController *viewController1, *viewController4;
UITableViewController *viewController2, *viewController3;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
viewController1 = [[FirstViewController alloc] initWithNibName:#"First_iPhone" bundle:nil];
viewController2 = [[Tips alloc] initWithNibName:#"Table" bundle:nil];
viewController3 = [[Favorites alloc] initWithNibName:#"Test_iPhone" bundle:nil];
viewController4 = [[SecondViewController alloc] initWithNibName:#"Second_iPhone" bundle:nil];
}
You are initing an UITabBarController and set 4 UIViewControllers as the corresponding UITabbarViewControllers. Since two of them are normal UIViewControntroller and two are UITableViewController there can not be a navigation bar. You have to load the viewController where you'd like the navbar form a UINavigationController. The correct way would be (assuming vc3 is the one where you'd like the navbar):
UIViewController *viewController1, *viewController4;
UITableViewController *viewController2, viewController3;
UINavigationController *vc3NavController;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
viewController1 = [[FirstViewController alloc] initWithNibName:#"First_iPhone" bundle:nil];
viewController2 = [[Tips alloc] initWithNibName:#"Table" bundle:nil];
viewController3 = [[Favorites alloc] initWithNibName:#"Test_iPhone" bundle:nil];
vc3NavController = [[UINavigationController alloc] initWithRootViewController:viewController3];
viewController4 = [[SecondViewController alloc] initWithNibName:#"Second_iPhone" bundle:nil];
}
Then load the vc3NavController instead of viewController3 as the corresponding tab.
So you have: UITabBarController -> UINavigationController -> YourViewController
Maybe Creating a Navigation Interface will help you too.
I have subclass of UINavigationBar.
#interface MyNavigationBar : UINavigationBar
Made some changes and now want that my application NavigationController would use it:
_navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
[_window addSubview:[_navigationController view]];
[self.window makeKeyAndVisible];
I want that _navigationController would have MyNavigationBar
How this could be done ?
Thanks.
You have to create a xib with a UINavaigationController in it. You can then select the navigationBar in Interface Builder and change the class to your subclass of UINavigationBar.
Then to make this a little easier to instantiate I add a category to `UINavigationController like:
#interface UINavigationController (DSCNavigationController)
+ (UINavigationController *)dsc_navigationControllerWithRootViewController:(UIViewController *)rootViewController;
#end
#implementation UINavigationController (DSCNavigationController)
+ (UINavigationController *)dsc_navigationControllerWithRootViewController:(UIViewController *)rootViewController;
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"DSCNavigationController" owner:nil options:nil];
NSAssert(1 == [topLevelObjects count], #"DSCNavigationController should have one top level object");
UINavigationController *navigationController = [topLevelObjects objectAtIndex:0];
NSAssert([navigationController isKindOfClass:[UINavigationController class]], #"Should have a UINavigationController");
[navigationController pushViewController:rootViewController animated:NO];
return navigationController;
}
#end
At the top of the class that uses it makes sure to import the category in my case it looks like
#import "UINavigationController+DSCNavigationController"
Then using it looks something like
MyViewController *myViewController = [[MyViewController alloc] init];
UINavigationController *navigationController = [UINavigationController dsc_navigationControllerWithRootViewController:myViewController];
UINavigationController has a read-only property
#property(nonatomic, readonly) UINavigationBar *navigationBar
since it is read-only you have to subclass UINavigationBar and override this property or make it read-write.E.g. :
MyNaviagtionBar *myBar = [[MyNavigationBar alloc] init];
_navigationController.navigationBar = mybar;
Or subclassing:
MyNavigationController.h
#class MyNavigationBar;
#interface MyNavigationController : UINavigationController
#property(nonatomic, strong) MyNavigationBar *navigationBar;
#end
MyNavigationController.m
#implementation MyNavigationController
#synthesize navigationBar = _navigationBar;
#end
And then change
_navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
to
_navigationController = [[MyNavigationController alloc] initWithRootViewController:self.viewController];