Pushing ViewController gives NSInvalidArgumentException - ios

I'm a newbie iOS developer, recently developed several Android apps, but I'm not familiar with iOS jargon. Let me explain my problem.
I want to use two different UIViewController. I've created .h and .m files for both controller. My plan is to push the secont view controller on top of the first view controller five seconds after the first view controller appears on the screen. I mean the first view controller is something like splash screen or similar.
Here is my contribution. In the first view controller, I defined (one of them implemented of course) these two method:
-(void) pushSecondController {
SecondViewController *secondController = [[SecondViewController alloc]
initWithNibName: nil
bundle: NULL];
[self.navigationController pushViewController: secondController animated: YES];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self performSelector: #selector(pushViewController:animated:)
withObject: nil
afterDelay: 5.0f];
}
And the second view controller looks like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.title = #"Second Controller";
}
I've changed only viewDidLoad method. When I ran the simulator, first view controller worked well and waiting 5 seconds and crashed. Output looks like:
2012-08-24 10:46:34.104 NavApplication[20355:f803] -[ViewController pushViewController:]: unrecognized selector sent to instance 0x6e7f780
2012-08-24 10:46:34.107 NavApplication[20355:f803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ViewController pushViewController:]: unrecognized selector sent to instance 0x6e7f780'
Let me ask one more question: I know there are differences between methodName and methodName:. Can anyone explain what's difference?
Any help would be appreciated.
UPDATE:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
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 = self.viewController;
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
[self.window makeKeyAndVisible];
[self.window addSubview: self.navigationController.view];
return YES;
}

Change #selector(pushViewController:animated:) to #selector(pushSecondController).

As mentioned above, you probably want to change your performSelector command to:
[self performSelector: #selector(pushSecondController)
withObject: nil
afterDelay: 5.0f];
because you want it to call your pushSecondController method, and not pushViewController:animated:.
Regarding your second question: the difference between methodName and methodName: is that the : at the end of methodName: signifies that this method takes a parameter. So, you could have the following methods:
- (void)listItems
{
// ...
}
- (void)insertItem:(NSDictionary *)item
{
// ...
}
When passing a reference to them into #selector, for the first method you'd just do #selector(listItems), because it takes no parameters, and for the latter you'd do #selector(insertItem:) because it takes a parameter.
UPDATE
Just saw your applicationDidLaunch code. You probably want to rearrange things so that you add your ViewController to your UINavigationController, and then set the UINavigationController as the rootViewController of your window. Like so:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}

please change your didFinishLaunchingWithOptions method to:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}

Related

starting ios project without storyboard

Im having some troubles to start an iOS app using xibs instead of storyboard. The problem is that im getting a black screen and the first view controller is not being called (added break point to viewDidLoad method).
In the app delegate header i have declared this:
#property (strong, nonatomic) UIWindow window;
#property (strong, nonatomic) ViewController *viewController;
And in the didFinishLaunchingWithOptions method i have this implementation:
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
navController.navigationBarHidden = YES;
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
Looking over some forums i found that i should be allocing the window so i added this as the first line of the function
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
The problem is that, when i do this, the app crashes after returning from didFinishLaunchingWithOptions method (SIGABRT without any trace).
I also tried to make the navController a property and also instantiating a default UIViewController class initing the same xib
What am i doing wrong?
Thanks and regards
Hope this helps you:
Delete the view controller and storyboard file and new viewController.h,viewController.h.m ,viewController.xib file.
#import "AppDelegate.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
#synthesize viewCOntrollerobj;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewCOntrollerobj = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self.viewCOntrollerobj];
//navController.navigationBarHidden = YES;
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
To change your project to use xibs instead of storyboards start by creating a xib for each view controller. You will need to change the File's Owner to class to the view controller you are creating the xib for. Then link the File's Owner view outlet to the view in the xib.
After that, select your app target and change the Main Interface drop down to be empty. Now you can delete the storyboard file.
Finally, initialize your window in the app delegate's application:didFinishLaunchingWithOptions: method and set your initial view controller as the root view controller of the window. Then call makeKeyAndVisible on your app delegate's window and you should be good to go.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [UIWindow new];
self.window.rootViewController = [ViewController new];
[self.window makeKeyAndVisible];
return YES;
}
In xCode 11:
Step1:
-> Delete the storyBoard file
Step2:
Under yourProject > General > deployment info > main interface -> delete reference to storyboard
Step 3:
In info.plist > Application Scene Manifest > Scene Configuration > Application Session Role > item 0 > storyboard name
-> Delete the line
Step 4:
In SceneDelegate.m
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.windowScene = (UIWindowScene *)scene;
self.window.rootViewController = [[UINavigationController alloc]
initWithRootViewController:ViewController.new];
[self.window makeKeyAndVisible];
}
make sure to import your viewController headfile like so: #import "ViewController.h"
OK, at last i got it.
What i had to do is just add again
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
After this, just delete the .h, .m and .xib and create them again.
For any reason its working fine now.
This is a kind of "out of the box" solution, so it is irrelevant to your code. Specially since I don't see anything wrong with your code.
I had the same problem and tried for a long time to fix the code, what worked for me was finding an example project (in github for example) that uses xibs.
Download it and then edit it to make your application it is guaranteed to work. It is a shame that Xcode wants to force us to use their storyboards with these kinds of problems.
I didnt try with XIB, but this thing is working fine here:::
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.viewController = [[ViewController alloc] init];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
navController.navigationBarHidden = YES;
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
// Override point for customization after application launch.
return YES;
}
and in ViewController's viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor greenColor]];
// Do any additional setup after loading the view, typically from a nib.
}
And the green color comes on the screen.
Initialize the window before setting the root view controller for the window.
That's the only problem that i see in you code, as the rootViewController is set to a nil window, and after that you are initializing.
Leave main interface empty
Add new ViewController.xib to the project and mark its file's owner class as "ViewController"
In AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
NSArray* xibContents = [[NSBundle mainBundle] loadNibNamed:#"ViewController"
owner:nil
options:nil];
ViewController* vc = [xibContents objectAtIndex:0];
UINavigationController *navigationController =
[[UINavigationController alloc] initWithRootViewController:vc];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
build and run
In Swift 3.0
//MARK: Initial View Controller
func initialViewController(){
self.window = UIWindow(frame: UIScreen.main.bounds)
let rootViewController = UIViewController(nibName: "HomeVC", bundle: nil)
let navigation : UINavigationController = UINavigationController(rootViewController: rootViewController)
navigation.isNavigationBarHidden = true
self.window?.rootViewController = navigation
self.window?.makeKeyAndVisible()
}
in appdelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
initialViewController()
return true
}
Xcode 11 with SceneDelegate
In SceneDelegate.m
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.windowScene = (UIWindowScene *)scene;
self.viewController = [[ViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
}
No need to do anything in AppDelegate.m

NavigationController presenting ViewController twice

I installed third party library using pods, which has it's own navigationController. I my existing project I am setting the rootViewController in the app delegate. I am pushViewController to the library ViewController (which is in it's own navigation stack). When I exit and then push to the library for a second time the ViewAlready seems to be there before transitioning the same view over the top.
In my appDelegate...
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
appbarViewController = [[AppBarViewController alloc] init];
[self loadNormalFlow];
[self.window makeKeyAndVisible];
}
- (void)loadNormalFlow
{
self.navigation = [[UINavigationController alloc]initWithRootViewController:appbarViewController];
self.window.rootViewController = self.navigation;
[self.navigation setNavigationBarHidden:YES];
}
-(void)displayLibraryView
{
ACSViewController *acs = [[ACSViewController alloc] init];
[self.navigation pushViewController:acs animated:nil];
}
Within library ViewController class to return back to original rootViewController i am using
[[UIApplication sharedApplication].delegate performSelector:#selector(loadNormalFlow)];
I seems like it is not properly dismissing the library ViewController, or it does a push twice? Any idea?

Can [self.window makeKeyAndVisible]; be called before setting rootviewcontroller

My requirement is that UITabBarController is the rootviewcontroller and on very first time of app launch I want to show login procedure which is inside UINavCon, and I am displaying it through presentViewController.
I dont want the UITabBarController visible for first time and dont want to how login UINavCon popping as modal.
I want to make user experience that if app starts for first time login UINavCon should be visible. So here is my code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];//is it correct to call it here?
LoginVC *loginObj = [[LoginVC alloc]init];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:cellPhoneNumber];
self.tabBarController = [[UITabBarController alloc]init];
self.window.rootViewController = self.tabBarController;
[self.tabBarController presentViewController:self.navigationController animated:NO completion:^{}];
return YES;
}
I am calling [self.window makeKeyAndVisible]; on second line right after uiwindow alloc init. Is it correct do this or I can experience problems like viewcontroller not receiving events or orientations notifications?
you can call it whenever you want. Calling it affects the window's z-index and screen property.
it doesnt depend on any specific content being set.
You haven't mentioned that whether you got the code working or not by using your implementation. Anyways I have done similar kind of implementation recently where we need to present login controller and then tabBarController after logging in, so just sharing my implementation.
Create your login controller and present it in didFinishLaunching method.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
LoginController *loginCObj= [[[MainScreenController alloc]init]autorelease];
UINavigationController *navigationControllerObj = [[[UINavigationController alloc]initWithRootViewController:loginObj]autorelease];
self.window.rootViewController = navigationControllerObj;
[self.window makeKeyAndVisible];
After that on succesful login in your login view controller, call an appDelegate public method
In login controller
AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDel applicationLoggedInSuccesfully];
In your appDelegate file, add a method like this:
-(void)applicationLoggedInSuccesfully{
UINavigationController *nv1 = [[[UINavigationController alloc] initWithNibName:nil bundle:nil]autorelease];
TabController1 *v1 = [[[TabController1 alloc] initWithNibName:nil bundle:nil]autorelease];
[nv1 pushViewController:v1 animated:NO];
UITabBarController *tabController = [[[UITabBarController alloc] init]autorelease];
tabController.viewControllers = #[nv1];
tabController.delegate = self;
self.window.rootViewController = tabController;
[self.window makeKeyAndVisible];
}
Hope it will help you.

iOS Application launch black screen, UINavigationController, Nib, RootViewController

I've got the following app, whose RootViewController is named TopicsViewController.
When I run it, there aren't any errors or breaks but the screen is black. No table, populated or empty, just a black screen. Not sure which of the following is happening:
Is there something wrong with my application didFinishLaunchingWithOptions method in relation to a parser initlizing in it?
Is it something to do with my nib file for the TopicsViewController?
I can show more code from my TopicsViewController class if needed.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
///////////////////////////////////////////
***initializing code for parser which populates TopicsViewController (not shown to save space)*****
///////////////////////////////////////////
UIViewController *rootController =
[[TopicsViewController alloc]
initWithNibName:#"TopicsViewController" bundle:nil];
navController = [[UINavigationController alloc]
initWithRootViewController:rootController];
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window addSubview:navController.view];
[self.window makeKeyAndVisible];
return YES;
}
Instead of:
[self.window addSubview:navController.view];
Write:
self.window.rootViewController = self.navController;

Basic table program in iOS - How can I tell my table to reload data from the application delegate?

I've got your standard table application built right now. Window has a UINavigationController as its rootViewController, and that UINavigationController was initialized with its rootViewController as my custom UITableController.
My applications table data changes over time. If I open my application up from a suspended state then my data is stale. How do I get applicationWillEnterForeground to update my data? I tried something awkward like
- (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];
HabitsTable* vc = [[HabitsTable alloc] init];
[vc initCoreData];
UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:vc];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[[[[self window] rootViewController] navigationController] rootViewController]
}
But, no surprise, that doesn't work. I'm not sure how to get at my UITableController?
I'd recommend using the NSNotificationCenter. You can see a nice example of how to use the class here.
I believe your close try:
UINavigationController *navController = (UINavigationController*)[[self window] rootViewController];
HabitsTable *tableView = (HabitsTable*)[navController topViewController];

Resources