reinitialize root view in iOS - ios

One would think I can easily find an answer to this question, and perhaps I missed it, but here goes.
My app contains a few views of which the main view displays a bunch of information it progressively collects from a user, the mic and and the camera through the other views. It is all supposed to end with one big climactic "submit button." At that point the data gets safely stored (currently in an sql database... but that's another story).
Once that is done, I want the whole process to start over which means reinitializing the view to a virgin state. In android, I can throw a new intent and destroy the old one.
I gather I'm supposed to start with the app delegate (see code below). Now the question is, where do I go from here?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.mainViewController = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.window.rootViewController = self.mainViewController;
self.mainViewController.managedObjectContext = self.managedObjectContext;
[self.window makeKeyAndVisible];
return YES;
}

I would create the RootViewController as my starting position. When the rootViewController loads I would initialize and add my First data input process. This way when I hit submit I would call popToRootViewController, and when The rootViewContoller Loads it would initialize and load the first data input process again.

So after a fair share of digging around, and trial and error. I found something that works the way I want it to.
I created a special function in the app delegate which executes the following:
- (void) newScreen
{
self.mainViewController = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.window.rootViewController = self.mainViewController;
self.mainViewController.managedObjectContext = self.managedObjectContext;
}
Then from main view controller, I call that function
[(AppDelegate *)[[UIApplication sharedApplication] delegate] newScreen];
Easy as pie...

Related

Error "Application windows are expected to have a root view controller" (iOS)

I've created a blank iPhone app project and would like to show a full-screen advertisement during app launch.
I tried to install the ad by following this guideline: https://github.com/mopub/mopub-ios-sdk/wiki/Interstitial-Integration-For-iOS
That's what I've done finally:
Actually all codes are just copied from the previous link.
However, an error shows when app runs:
Application windows are expected to have a root view controller at the end of application launch
I think this error may probably related to the loadView method, because if I remove the loadView method, the error disappeared.
In fact, this error seems common as it can be easily searched on the internet, but I don't know how loadView is related to it, and how can it be solved in my case.
Any solutions? Thanks a lot.
You probably need to do this:
Add
#import "ViewController.h"
to the top of AppDelegate.m
And in AppDelegate.m, your application:didFinishLaunchingWithOptions: method should have some code like this.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ... Other code
// Override point for customization after application launch.
ViewController *viewController = [[ViewController alloc] init];
self.window.rootViewController = viewController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
UIViewController *vc = [[UIViewController alloc] init];
[vc.view addSubview:self.tab_controller.view];
[self.window setRootViewController:vc];
OR
UIViewController *vc = [[UIViewController alloc] init];
[vc.view addSubview:yourClass.view];
[self.window setRootViewController:vc];
If you started with an empty template and added a storyboard, you need to do a couple of things:
You need to delete all the lines (except return statement) inside didFinishLaunchingWithOptions
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return YES;
}
In project settings ->General, select your storyboard as the main interface
Attached snapshot to help you
At the right side check there is one option under attribute inspector which asks to set as "is rootView controller"

ARC - managing memory - views are not released and allocations grow until app crashes

I have been having some memory management issues and random crashes with my app. I have done a lot of work on it to try to clean up the code generally and have converted the project to ARC.
I now have a clear view on the problem - essentially the app does not release views so as a user moves through the app each view is reloaded and retained until finally the app crashes due to memory issues.
I have a UINavigationController. My app runs only in landscape left orientation. When i use
[window setRootViewController:viewController];
on load and then
[self.window addSubview:[finalViewController view]];
the new view is displayed in portrait - if i rotate it to landscape left with code when i load it in, then all kinds of other random issues come up.
If instead of addSubview i use
[self.viewController.view removeFromSuperview];
[self.window setRootViewController:finalViewController];
viewController = nil;
self.viewController = nil;
window.viewController = nil;
rotation is ok but views are not released and i have a memory issue with the app and it crashes eventually. Any thoughts would be awesome - appreciate i'm probably missing something fairly basic here. Thanks & happy holidays!
How are you loading new views in your app? If you are using a UINavigationController, your AppDelegate should start something like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
RootViewController* rootController = [[RootViewController alloc] init];
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:rootController];
[self.window setRootViewController:navController];
[self.window makeKeyAndVisible];
return YES;
}
To load another view(say from a button press) you will do something like this from within the root view:
SecondViewController *secondView = [SecondViewController alloc] init];
[self.navigationController pushViewController:secondView animated:YES];
This will make the UINavigationController responsible for memory management of your views.
As for rotation, that is handled by giving each of your ViewControllers this method:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft) return YES;
return NO;
}
Aslong as you are using the UINavigationController the way it is meant to be used, you should not have any non-releasing views. You should read into the UINavigationController: http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html
Another possibility is that the childviews of your view controllers have strong references to their parent view/controller. This will stop a parent viewcontroller from deallocating due to it giving its child a retain count of 1 and the child giving the parent a retain count of 1 as well. Here is a SO post with information on strong & weak references: Objective-C declared #property attributes (nonatomic, copy, strong, weak)

Converting a simple app to have a tab bar

I have a question that is similar to this SO question, but slightly different (or my skills don't allow me to follow the directions with confidence). I have an existing game app that has one view controller and one nib and works fine. I want to convert it to have a tab bar controller. I want the original, existing view controller to be on the first tab, and I wrote a new view controller and a new nib for the second tab, which will be dedicated to game settings. At this stage, the app builds and runs fine with the new nib and view controllers in the project (but with no further edits -- no attempt to add the tab bar controller etc). The modified app should simply have two views each accessible from one of the two tabs.
Sorry for the long bkgnd. I'm following the accepted answer to the above-referenced question. The first 4 steps I have done or can do. The 5th step is to Delete the old version of your Main View Controller from the NIB file and also remove the IBOutlet property from the Application Delegate. I don't think I have such an IBOutlet in my app (which is different from the OP's app). Should I delete the object view controller shown in this list? Or am I on the wrong track here?
Additional Info
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Set up view controller & load a clean view
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[P3ViewController alloc] initWithNibName:#"P3ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
NSLog(#"P3ViewController now active");
[self.window makeKeyAndVisible];
return YES;
}
This should get you in the right direction...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UITabBarController *tbc = [[UITabBarController alloc] init];
YourNewViewController *ynvc = [[YourNewViewController alloc] initWithNibName:#"YourNewViewController" bundle:nil];
YourCurrentViewController *ycvc = [[YourCurrentViewController alloc] initWithNibName:#"YourCurrentViewController" bundle:nil];
[tbc setViewControllers:[NSArray arrayWithObjects:ynvc, ycvc, nil]];
self.window.rootViewController = tbc;
[self.window makeKeyAndVisible];
return YES;
}

Hiding the master view in a Split View Controller

I am new to iPad development (or iPhone for that matter :) ) and I am building an app with a Split View Controller.
The thing is the first screen should be a single screen. I want the user to write user/pass data to connect to a remote server, and there's not really anything to show in the master view.
I know I can return YES in the splitViewController:shouldHideViewController:inOrientation:, and that works fine for the first screen, but I'd like to get the two views when the user taps the login button and the credentials are validated.
I can put some condition in shouldHideViewController and that shows the two views in the second screen and only the detail in the first, but shouldHideViewController is only called if I rotate my iPad, not when I perform the segue.
Do you have any tips to do this? Should I change my UI approach to something else? Any suggestions are welcome.
starting from scratch is a good idea. You have more control over whats going on IMO.
At your starting point you want to add your LoginViewController.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.loginController = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Later when the authentication process has finished you want to continue with SplitView, right?
- (void)continueWithSplitView {
UINavigationController *leftNav = [[UINavigationController alloc] initWithRootViewController:self.masterViewController];
UINavigationController *rightNav = [[UINavigationController alloc] initWithRootViewController:self.detailViewController];
self.splitViewController.viewControllers = [NSArray arrayWithObjects:leftNav, rightNav, nil];
self.view.window.rootViewController = self.splitViewController;
}
Notice that in both methods your desired viewController is set as the rootViewController property of UIWindow. This will automatically add the view of your controller as the top level view in UIWindow.
Furthermore make sure that you are following the MVC pattern e.g. a model object for your credentials organisation.

How to open a ViewController before application starts in iOS

I am working in iOS 5,and before loading my application,I want to open a another view controller,where the user should enter some data,for eg.password and when the password matches ,application will be opened,I am not getting how to do this..I tried some code ,which I have written below
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if(somecondition)
{
ViewController *View =[[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
[_window addSubview:View.view];
}
return YES;
}
But I dont know whether it is a right way,so friends,please help me out..
Regards
Ranjit
You should use
[self.window setRootViewController:yourViewController]
instead of addSubview to your window.
BTW, searching before asking is a good habit. ;)
If you want to show a view like the loginView or loadingView, you can set it as your rootViewController, when did loaded, you can reset your rootViewController.
Note, in your ProjectAppDelegate.m, you can get window
by self.window, and in other child view controller's, you'll need
[[[UIApplication sharedApplication] delegate] window]
to get your main window.
Another simple way to meet your requirement is that you can just present a modalView before showing your app. Dismiss it after done and then start your app.
You can get more suggestion HERE.
BTW, I'm sorry I didn't get your comments' notification when you are write at other users comment area a few days ago. :( You should add # before the user's name when you comment at somewhere else.
You can create some bool variable for checking is this a first start or another. The best place to store this bool is NSUserDefaults. Well, if this is a first start then show your LoginViewController, if not - execute regular code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIViewController *startVC = nil;
if (isFirstLaunch){
startVC = [[[LoginViewController alloc] initWithNibName:#"LoginView" bundle:nil] autorelease];
}
else{
startVC = [[[WorkspaceViewController alloc] initWithNibName:#"WorkspaceView" bundle:nil] autorelease];
}
navController = [[UINavigationController alloc] initWithRootViewController:startVC];
[self.window makeKeyAndVisible];
[self.window addSubview:navController.view];
return YES;
}

Resources