Known effort to update MGSplitViewController for iOS5 and Storyboards? - ios

I'm working on an iPad app that will need to hide/show the master controller of a split view.
Related SO answers note Matt Gemmell's MGSplitViewController:
How to hide master view in UiSplitviewcontroller in ipad
How do I hide the master part of a UISplitViewController programatically?
Integrate MGSplitViewController in Universal App
MGSplitViewController using Storyboards
MGSplitViewController would be perfect - even providing a way to adjust the ratio of master-to-detail views.
Fantastic! Except it doesn't play nice with the latest Xcode using storyboards and ARC.
I see a pull request (from 9 months ago) to convert to ARC for iOS4 but that still leaves it needing some work to be storyboard friendly.
Does anyone know of ongoing effort to update this jewel of open source to behave properly in the latest iOS development environment?
Failing that, examples/tutorials of how to integrate it into an Xcode storyboard/iOS5 project would be very useful.

It looks like if you wait long enough, every good package will get the attention it's due.
Thanks again to Matt Gemmell for a great package, and kudos to Heath Borders for taking the initiative.
Heath Borders port to iOS 5.1

I was able to work around the storyboard issue. I had a universal app with master detail storyboard setup so I left them all in place and changed the initialization of the app to not use storyboards and instead programmatically set it up in my applicationDidFinishLaunching like so:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
self.masterController = [storyboard instantiateViewControllerWithIdentifier:#"masterController"];
self.detailController = [storyboard instantiateViewControllerWithIdentifier:#"detailController"];
self.splitViewController = [[MGSplitViewController alloc] init];
self.splitViewController.masterViewController = self.masterController;
self.splitViewController.detailViewController = self.detailController;
ACALandingVC* landingVC = [self.detailController.childViewControllers objectAtIndex:0];
landingVC.splitController = self.splitViewController;
self.splitViewController.delegate = landingVC;
//self.splitViewController.splitWidth = 5;
self.splitViewController.allowsDraggingDivider = YES;
self.splitViewController.dividerStyle = MGSplitViewDividerStylePaneSplitter;
self.splitViewController.splitPosition = 350;
self.splitViewController.splitWidth = 10;
self.window.rootViewController = self.splitViewController;
}
else {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
UITabBarController* firstVC = [storyboard instantiateInitialViewController];
self.window.rootViewController = firstVC;
[[UINavigationBar appearance] setTintColor:[UIColor lightGrayColor]];
}
[self.window makeKeyAndVisible];
My AppDelegate.h looks like:
#class MGSplitViewController;
#interface ACAAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) MGSplitViewController* splitViewController;
#property (nonatomic, strong) UITabBarController* masterController;
#property (nonatomic, strong) UINavigationController* detailController;
#end

Related

How do I start another view controller with no storyboard?

I'm not using a storyboard or anything. I'm just creating the cocoa classes and linking them up individually. I can get to load up the default View Controller which is SplashViewController but i can't get past there.
I have experience in php, android programming and python, but i'm totally clueless on how Obj-C and how the iOS framework works :(
SplashViewController.m
-(void)initializeInterface
{
//Initialize start button
[self.startButton addTarget:self action:#selector(startActivity) forControlEvents:UIControlEventTouchDown];
//Initialize fading backgrounds
[self animateImages];
}
-(void)startActivity
{
PhoneViewController *phoneView = [[PhoneViewController alloc] initWithNibName:#"PhoneViewController" bundle:nil];
[self.navigationController pushViewController:phoneView animated:YES];
}
SplashViewController.h
#import <UIKit/UIKit.h>
#import "PhoneViewController.m"
#class PhoneViewController;
#interface SplashViewController : UIViewController
#property (strong, nonatomic) PhoneViewController * phoneViewController;
#property UIImage *splashbg1;
#property UIImage *splashbg2;
#property (nonatomic, retain) IBOutlet UIImageView *splashbg;
#property (nonatomic, retain) IBOutlet UIButton *startButton;
-(void)initializeInterface;
-(void)animateImages;
-(void)startActivity;
#end
EDIT
classAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
//Move from delegate view controller to root view controller
self.window.rootViewController=[SplashViewController new];
[self.window makeKeyAndVisible];
return YES;
}
Wrap your splash view controller in a navigation controller.
Otherwise, the navigationController property of your splash view controller is nil and pushViewController has no effect.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController: splashViewController];
To move from one UIViewController to other UIViewController, you can try the following things
If SecondViewController *secondViewController is the UIViewController you want to move in to, then your can do the following:
[self presentViewController: secondViewController animated:YES completion:nil];
This is when you UIViewController is not embedded inside a UINavigationController.
It is possible to create your view controllers entirely in code without using Storyboards or XIB files, but it's not recommended. It's like trying to write a complex user application in assembler. The state of the art has evolved since the days when that was necessary. There are better tools. Use them.
Creating everything yourself is both quite complex and not very well documented. You are setting yourself up for a very frustrating, error-prone process. I've been doing iOS development pretty much full time since 2009, and I would not attempt this.
That being said, if you are a masochist, you would create your view controller using initWithNibName:bundle:, passing in nil for both parameters, and then implement the loadView method. In loadView you're create your view hierarchy and install it.
If you are new to iOS/Objective-C, DO NOT DO THIS. It is like trying to write a kernel device driver in machine code as your first foray into UNIX.
Change you AppDelegate method as below -
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
UINavigationController *navcon = [[UINavigationController alloc]initWithRootViewController:[SplashViewController new]];
//Move from delegate view controller to root view controller
self.window.rootViewController=navcon;
[self.window makeKeyAndVisible];
return YES;
}
Problem in your code, you have not taken any navigationController, that enables you push or pop UIViewController. Doing above you can use your method -(void)startActivity to Start a new ViewController.

navigation controller pushViewController not working

I'm creating an application that has 2 main view controllers at the moment. The app loads into the initial viewController, and clicking a button inside should bring up the second viewController. Here's what I have:
AppDelegate.h
#import <UIKit/UIKit.h>
#import "ViewController1.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) ViewController1 *mainViewCtr;
#property (strong, nonatomic) UINavigationController *navigationController;
#end
AppDelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application {
_mainViewCtr = [[ViewController1 alloc] initWithNibName:#"mainViewCtr" bundle:nil];
_navigationController = [[UINavigationController alloc] initWithRootViewController:_mainViewCtr];
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_window.rootViewController = _navigationController;
_navigationController.delegate = self;
_navigationController.navigationBarHidden = YES;
[_window addSubview:_navigationController.view];
[self.window makeKeyAndVisible];
}
and my button method inside viewcontroller1:
- (IBAction)SessionNickNameSubmit:(id)sender {
ViewController2 *secondViewCtrl = [[ViewController2 alloc] initWithNibName:#"secondViewCtrl" bundle:nil];
[self.navigationController pushViewController:secondViewCtrl animated:YES];
}
but when I click the button the view doesn't change. I tried debugging and the code is hit, but nothing happens.
am I missing a setting somewhere?
UPDATE
I've updated all viewController variable names:
instead of ViewController1/2 I'm using mainViewCtrl and secondViewCtrl
but still no use :(
You made a typo:
it's
_window.rootViewController = _navigationController;
not
_window.rootViewController = _joinViewController;
And NeverHopeless's suggestion is also spot on. It's probably the typo AND the fact that you add your second viewcontroller as ViewController2 and not using a proper variable name.
Another suggestion is making a storyboard (if you are not using one) and adding a segue for the transition. Simply assign the segue processing to the button. Like this:
-(IBAction)SessionNicknameSubmit:(id)sender
{
[self performSegueWithIdentifier:#"identifier" sender:self ];
}
Here is a nice description of how it works and how to use it plus some useful pointers!
Obj-C is a case sensitive language, class name and instance name should not be the same like ViewController2. Try like this:
- (IBAction)SessionNickNameSubmit:(id)sender {
ViewController2 *viewController2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
[self.navigationController pushViewController:viewController2 animated:YES];
}
The reason is that you have set the window's rootViewController to ViewController1.
You need to set you navigation controller to the window's rootViewController.
So that when you try to access the self.navigationController on the press of the button, it will access the navigation controller in which the self resides i.e. your window's rootViewController now.
Then it will push the next view controller properly.
After looking at almost every tutorial and every stack overflow answer, I finally found a solution that worked. I had to make an instance of the storyboard in the app delegate and use that to create my first view controller instance.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.joinViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController1"];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:joinViewController];
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
navigationController.navigationBarHidden = YES;
_window.rootViewController = navigationController;
[_window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
I think the problem was that when I was creating an instance of ViewController, it was creating a new instance and binding the navigation controller to it (independent of the view controller that was showing up in the simulator). So when I was using the push method it wasn't recognizing self.NavigationController (that's why NSLog(self.NavigationController == nil) was logging 1

Losing left menu when going back PKRevealController

I'm implementing PKRevealController in an existing project. This project uses Storyboards, but user is able to play Cocos2D 2.0 game within the app.
My problem is that when user goes out of Cocos2D, I use a notification (notification center) on my navigation controller (that controls the Cocos2D game) to segue to my main view, but when it does the segue the PKRevealController doesn't work anymore.
I implement the PKReveal on my AppDelegate, so I suppose I should (somehow) implement it somewhere i can re-implement it when i exit a Cocos2d game.
Any ideas? Thank you!
If anyone has the same problem, there's how I solved this problem:
Created a new UIViewController in Storyboard, and embed it in a NavigationCotroller
Created my InitialViewController for this new ViewController and implemented both <PKRevealing, UIApplicationDelegate>.
Created thise properties in it:
#property (nonatomic, strong) PKRevealController *revealController;
#property (strong, nonatomic) UINavigationController *myNavController;
#property (strong, nonatomic) UIWindow *window;
On viewDidLoad did self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; (like on my AppDelegate)
Finally on viewDidAppear method:
FrontViewController *frontViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"FrontViewController"];
PortraitAppNavigationController *frontNavigationController = [[PortraitAppNavigationController alloc] initWithRootViewController:frontViewController];
LeftMenuViewController *leftViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"LeftMenu"];
// Step 2: Instantiate.
self.revealController = [PKRevealController revealControllerWithFrontViewController:frontNavigationController leftViewController:leftViewController];
// Step 3: Configure.
self.revealController.delegate = self;
self.revealController.animationDuration = 0.25;
// Step 4: Apply.
self.window.rootViewController = self.revealController;
[self.window makeKeyAndVisible];

How to Add a New StoryBoard, and set it to become the Main StoryBoard xCode without error

Currently, I have a working app with a single storyBoard. The working app is based on master-detail view layout. I decided to add a new storyboard, and set it to become the main storyboard. When I click run, it will run and display a blank page, which is what I expected as I have not added any view controllers.
I am still new to objective-C, as such, there are many things that I still do not understand, Here comes the interesting part.
When I add a UIViewController(and associated it to a subclass of UIViewController) inside my newly changed Main storyboard, and then tried to run it, it displays an error.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController viewControllers]: unrecognized selector sent to instance 0x7569a80'
Under my AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
splitViewController.delegate = (id)navigationController.topViewController;
return YES;
}
I am not so sure what do I need to add to the code above. I did try the below line without success too,
UIViewController *viewController = (UIViewController *)self.window.rootViewController;
As such, how do I solve this problem?
Take storyboard file from New file-->ios-->user interface---> storyboard
create #property storyboard in appdelegate
like
#property (nonatomic, retain) UIStoryboard* storyboard ;
before implementation in .m file write:
#interface AppDelegate ()
#property (strong, nonatomic) UIViewController *initialViewController;
#end
This is to take refrence of initial viewcontroller.
then #synthesize storyboard in appdelegate.m
and then for navigation you can write in didFinishLaunchingWithOptions
//init storyboard
storyboard = nil;
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.0"))
{
CGSize result = [[UIScreen mainScreen] bounds].size;
if(result.height == 480)
{
storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhoneIOS5" bundle:nil];
NSLog(#"Version < 6");
// iPhone Classic
}
if(result.height == 568)
{
// iPhone 5
storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
NSLog(#"Version 6");
}
//NSLog(#"IOS 6");
}
else
{
storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhoneIOS5" bundle:nil];
//NSLog(#"IOS 5");
}
self.initialViewController = [storyboard instantiateInitialViewController];
//instantiateInitialViewController means it returns the arrow pointed view-controller on storyboard that is root view controller.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = self.initialViewController;
[self.window makeKeyAndVisible];
On Xcode 7 you can go to info.plist and set the key "Main storyboard file base name" to the name of your new Storyboard .
Example: You create a new storyboard file by going to file -> new -> file -> Storyboard file and you save it as "MyAwesomeUI.storyboard" then in info.plist you change the key of "Main storyboard file base name" to "MyAwesomeUI" .
Cheers!

Embedding UIPageControl inside a TabBarController stack

I'm building an application which has a TabBarController at the top level. Contained within one of the tabs there is a tableview, and when a row is selected, I'd like to go to a set of 5 views, controlled via a UIScrollViewDelegate and UIPageControl.
I've built a basic app with the UIScrollViewDelegate and UIPageControl, based Derek Bredensteiner's code in this answer: How do I use UIPageControl to create multiple views?
It works fine as a stand alone application, ie: when the ViewController code is called directly from the AppDelegate via:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
But when I try to call the same code from my tableview code, I am getting a black screen. I've also tried using presentModelViewController and I get the UIPageViewControl dots but the rest is black.
LearnPageViewController *phoneContentController = [[LearnPageViewController alloc] init] ;
// [self presentModalViewController:phoneContentController animated:YES];
[self.navigationController pushViewController:phoneContentController animated:YES];
I managed to get it to work by adding a new window property #property (nonatomic, retain) IBOutlet UIWindow *window; but it doesn't sound right. There is a window property up on the AppDelegate and now another one 2 levels down.

Resources