uitableviewcontroller, with xib, loaded from appdelegate, never loads? - ios

I have an ItemsViewController of type
#interface ItemsViewController : UITableViewController
Now this I call from the appdelegate in the didFinishLaunchingWithOptions like so
ItemsViewController *itemsViewController = [[ItemsViewController alloc] initWithNibName:#"ItemsViewController" bundle:nil];
// Create an instance of a UINavigationController
// its stack contains only itemsViewController
UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController:itemsViewController];
// Place navigation controller's view in the window hierarchy
[[self window] setRootViewController:navController];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
Now in ItemsViewController.m file I do hit this method :
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
but the problem here is that it never hit the viewdidload method?? What should I look for? I am confused!!

ok , well I found the problem, I've been doing so much editing of this project that I accidentally deleted the most important line in the beginning of the method didFinishLaunchingWithOptions. which is this :
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
Anyway, so I am going to kill myself now, feel free to recommend a method of death ( clorox cocktail, walk into traffic) , and if you wanna write some nice words about me to be published
in my eulogy too.
Thanks.

Related

Custom View Controller on launching

After a few years off the grid, I'm back programming a quick iOS application and I have to say it seems I need to get back on track. :D
I'm just trying to set-up a Login view upon launching the application and I am stuck with the following issue on which I've read about a lot but could not fix it. Simulation stops on the main.m (#autoreleasepool).
FYI: I am not using Xib or Storyboard as I'm trying to do everything programmatically.
libc++abi.dyLibL terminating with uncaught exception of type NSException
It is probably coming from one of the following.
LoginViewController.h:
#interface LoginViewController : UIViewController
#end
Test1 / LoginViewController.m:
I guess there should be a init method defined from UIViewController so I would not need to define one here.
#implementation LoginViewController
#end
Test2 / LoginViewController.m:
Trying to override with my custom init function. No luck as well.
#implementation LoginViewController
- (id) init
{
self = [super initWithNibName:nil bundle:nil];
return self;
}
#end
AppDelegate.m:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
LoginViewController *loginViewController = [[LoginViewController init] alloc];
// error here
self.window.rootViewController = loginViewController;
[self.window makeKeyAndVisible];
return YES;
Not sure exactly what went wrong here but it crashes right after seeing a black iPhone screen on the simulator.
Any help appreciated! ;)
Thanks.
Change this line
LoginViewController *loginViewController = [[LoginViewController init] alloc];
To
LoginViewController *loginViewController = [[LoginViewController alloc] init];

Init programmatic VC for Storyboard VC

I want to display a programmatically created ViewController in a storyboard ViewController. The ViewController of the Storyboard is of a different class as the 'programmatically' created ViewController.
I've got the following classes:
ViewController (linked to storyboard scene, and implementation happens here)
OnboardingVC (all elements are created over here)
I've tried the following:
-(id)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if(self){
self.onboardVC = [self generateFirstDemoVC]; // returns in an instance ofOnboardingViewController
self = (ViewController*)self.onboardVC;
}
return self;
}
This (obviously) crashes.
What I don't want is this:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window setRootViewController:self.onboardVC];
[self.window makeKeyAndVisible];
Because this doesn't take the setup in the storyboard into account, and I don't want that, because the VC needs to managed by a NavigationController. How do I accomplish that?
It sounds like you have a UINavigationController as the entry point to your storyboard. You can manipulate this navigation controller when the application launches, to add, remove, or replace view controllers, etc.
For example:
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
UIViewController* initialVc = [OnboardingViewController generateFirstDemoVC]; // or whatever
UINavigationController* nav = (id)_window.rootViewController;
nav.viewControllers = #[ initialVc ];
return YES;
}

PushViewController to current navigation controller from another class

I am creating a class object from my UIViewController and trying to push a controller from it, and it won't work.
I have been doing research but found nothing, any idea?
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.newClass = [[MyNewClass alloc] init];
self.newClass.view = self.view;
self.newClass.navigationController = self.navigationController;
[self.newClass connect];
}
...
#end
MyNewClass.h
#interface MyNewClass : NSObject<UINavigationControllerDelegate>
#property(nonatomic, retain) UIView *view;
#property(nonatomic, retain) UINavigationController *navigationController;
-(void) connect;
#end
MyNewClass.m
-(void)connect
{
OtherViewController * otherVC =
[[OtherViewController alloc] init];
self.navigationController pushViewController:otherVC animated:YES];
}
...
add folloeing code into appdelegate's didFinishLaunchingWithOptions method.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self copyDatabaseIfNeeded];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
[self.window makeKeyAndVisible];
return YES;
}
and then remove all other UINavigationController declaration and allocation. Like MyNewClass's NavigationVontroller. Because here you declare and allocate navigationcontroller in appdelegate so you can use it in whole app.
When viewDidLoad is called, the view has just been loaded but the view controller hasn't necessarily been added to a navigation controller yet. So using viewDidLoad as your trigger is not useful.
A better approach is to explicitly pass the navigation controller to the view controller when it's created. Or to implement didMoveToParentViewController: and do your configuration there.
You are pushing a viewController from a controller, which is not a part of navigationController, so first make it part of navigationController, then try

Clicking a button results in exe_bad_action

I created a brand new project and created a new view controller with a button in the view.
I am adding the view in application:didFinishLaunchingWithOptions
- (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];
BOOL introDisplayed = [[NSUserDefaults standardUserDefaults] boolForKey:kIntroScreenSeenByUser];
if(introDisplayed)
{
}
else
{
IntroView *introView = [[IntroView alloc] initWithNibName:#"IntroView" bundle:nil];
[self.window addSubview:introView.view];
}
[self.window makeKeyAndVisible];
return YES;
}
.h file
#interface IntroView : UIViewController
#property (weak, nonatomic) IBOutlet UIButton *clickMe;
- (IBAction)clicked:(id)sender;
#end
.m file
#import "IntroView.h"
#interface IntroView ()
#end
#implementation IntroView
#synthesize clickMe;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[self setClickMe:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)clicked:(id)sender {
NSLog(#"clicked");
}
#end
Clicking on the button results in a EXC_BAD_ACCESS(code=2 error. Any ideas? I am using ARC.
Thanks
UPDATE
Created a public property on the application delegate called "introViewController" and changed the application:didFinishLaunchingWithOptions
#synthesize introViewController;
- (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];
BOOL introDisplayed = [[NSUserDefaults standardUserDefaults] boolForKey:kIntroScreenSeenByUser];
introViewController = [[IntroView alloc] initWithNibName:#"IntroView" bundle:nil];
if(introDisplayed)
{
}
else
{
[self.window addSubview:introViewController.view];
}
[self.window makeKeyAndVisible];
return YES;
}
This solved the error.
You're creating your IntroView controller, and adding it's view as a subview, but the controller itself is released. I don't think that adding the view controller's view (and then letting ARC discard the controller itself) is an acceptable way to create a view.
Perhaps you could make the IntroView view controller a property of the app delegate class and therefore it won't be released by ARC.
Personally, I don't monkey around with the app delegate's creation of the views and controllers, but rather I let my target settings and my NIBs dictate that. I presume you're doing this because you want to have some intro screen. If I wanted an screen, I'd have my main view controller go ahead and present whatever intro I want. That way when the intro is dismissed (or popped off, depending upon whether you pushed or presented modally), my main view controller is still at the top (and useful methods like popToRootViewController work perfectly).

UIView doesn't become First Responder when parent UIViewController is set as RootViewController

I'm working on Chapter 7 of BNR's iOS Programming book and I've run into a problem. At the start of the chapter I setup a UIViewController (HypnosisViewController) with an UIView (HypnosisView) that responded to motion events in the previous chapter.
I create the UIViewController in the AppDelegate.m file:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
HypnosisViewController *hvc = [[HypnosisViewController alloc] init];
[[self window] setRootViewController:hvc];
...
}
In the HypnosisViewController, I set HypnosisView to become first responder:
- (void)loadView
{
// Create a view
CGRect frame = [[UIScreen mainScreen] bounds];
HypnosisView *view = [[HypnosisView alloc] initWithFrame:frame];
[self setView:view];
[view becomeFirstResponder];
}
And in HypnosisView I make sure to return YES to canBecomeFirstResponder. Unfortunately, the HypnosisView did not respond to motion events like before. When I eventually moved on, I made an interesting discovery. If I move HypnosisViewController into a UITabBarController, HypnosisView starts responding to motion events. The code looks something like this:
HypnosisViewController *hvc = [[HypnosisViewController alloc] init];
UITabBarController *tabBarController = [[UITabBarController alloc] init];
NSArray *viewControllers = [NSArray arrayWithObjects:hvc, <insert more objs here>, nil];
[tabBarController setViewControllers:viewControllers];
[[self window] setRootViewController:tabBarController];
Why didn't HypnosisView become first responder when HypnosisViewController was set as the RootViewController? Why did it start working once HypnosisViewController was placed inside another controller? What am I missing about RootViewController?
Thanks!
Your question is very apt. I'm also studying the same book and am on the same chapter. The thing is that before we used UITabBarController we would either use HypnosisViewController or TimeViewController. And we would then do [self.window setRootViewController:hvc] or [self.window setRootViewController:tvc] in the AppDelegate.m file. In that case setRootViewController method was calling loadView method internally. So if loadView should get called then becomeFirstResponder (which resides inside of it as a method call as per your code) also is supposed to get triggered. So internally canBecomeFirstResponder should get called
Now when we use UITabBarController, things tend to break. What happens is instead of loadView getting called via '[[self window] setRootViewController:tabBarController];' line of code, it gets called through '[tabBarController setViewControllers:viewControllers];'. So the bottomline is that rootViewController property (when set to tabBarController) does not call loadView method and hence 'becomeFirstResponder' is not called. You may argue that loadView does get called through '[tabBarController setViewControllers:viewControllers];' but setViewControllers is not used for setting root viewController.
When I faced this problem, I made an explicit call to becomeFirstResponder. Here's how:-
#implementation HypnoTimeAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions //method of UIApplicationDelegate protocol
{
NSLog(#"lets begin");
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
HypnosisViewController *viewController= [[HypnosisViewController alloc] init];
TimeViewController *viewController2= [[TimeViewController alloc] init];
NSLog(#"view controllers are done initializing!");
UITabBarController *tabBarController= [[UITabBarController alloc] init];
NSArray *viewControllers= [NSArray arrayWithObjects:viewController,viewController2, nil];
[tabBarController setViewControllers:viewControllers];//loadView of HypnosisViewController gets called internally since the 'app view' isn't going to load from a XIB file but from 'HypnosisView.m'.loadView method of TimeViewController loads its own view from the XIB file.
[self.window setRootViewController:tabBarController];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
#implementation HypnosisViewController
-(void)loadView{
NSLog(#"HypnosisView loading...");
HypnosisView *myView= [[HypnosisView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.view= myView;
[self configureFirstResponder];//configuring first responder
}
-(void) configureFirstResponder{
BOOL viewDidBecomeFirstResponder= [self.view becomeFirstResponder];
NSLog(#"Is First Responder set as HypnosisView? %i",viewDidBecomeFirstResponder);
}

Resources