How to autoload the first click of a button in iOS? - ios

I have a button created using the .xib file. I want the app to autoload the first question (meaning the ViewController to autoload the "showQuestion" method when the app first started. I am a beginner. How do you do it? Please help! Thanks!
ViewController.m
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
//call the init method implemented by the superclass
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
self.questions = #[#"What is your name?",
#"How old are you?",
#"Where are you from?"];
return self;
}
- (IBAction)showQuestion:(id)sender{
self.questionLabel.text = self.questions[currentIndex];
}
the AppDelegate.m file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
ViewController *vc = [[ViewController alloc] init];
self.window.rootViewController = vc;
return YES;
}

In your -viewDidLoad method of the view controller, just manually call the -showQuestion method.
i.e. in your ViewController.m, add this:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self showQuestion:nil];
}

Try like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
ViewController *vc = [[ViewController alloc] init];
self.window.rootViewController = vc;
// Autoload first question
[vc showQuestion:nil];
return YES;
}
ViewController.h
- (IBAction)showQuestion:(id)sender;

Related

iOS state restoration discarding navigation stack

tl;dr State restoration process appears to be happening, but the stack (non-root) view controllers are not ending up in the app after restoration completes.
I'm trying to implement state restoration in an app, which doesn't use any .nibs or storyboards. It's a fairly basic structure: the window's rootViewController is a UINavigationController whose own rootViewController and all other child view controllers are UITableViewControllers (eg, Window > Nav Ctrl > Table View Ctrl > Table View Ctrl > etc). None of the view controllers are ever repeated (ie each item on the stack is a distinct UITableViewController subclass)
As I have no view controllers being created with storyboards, I have the designated initializer for each view controller class setting the restorationIdentifier and restorationClass.
When the app is being restored, I am seeing decoding happening for each view controller that was present when the app went into the background (eg, the nav controller, the podcast list controller, and the podcast detail controller), but the end result of the restoration is always the navigation controller showing up with it's normal root view controller (the podcast list controller).
The problem seems very similar to this question, but I am definitely calling super in the encode- and decodeRestorableStateWithCoder: methods on my view controllers (when present), so that solution doesn't help me.
I have watched the WWDC videos and gone through many tutorials, and while I seem to be hitting all the requirements, something is not working the way it should be.
The only thing I can think is happening is the restoration is happening, but my default initialization code is replacing the restored navigation view controller stack with a "fresh" one that only includes the root. According to the WWDC video, the window and root view controller should be set up normally prior to state restoration, and that shouldn't impact the final app state after restoration.
I guess the one question mark for me is what should actually be happening in the viewControllerWithRestorationIdentifierPath: method of my UINavigationController. Should the rootViewController be set as I am doing? And if not, what else would happen? I couldn't actually find any working example code where a navigation controller was being restored and it wasn't created from a nib or storyboard. Other than that I'm stumped.
Implementation code
FLAppDelegate.m
# pragma mark - UIApplicationDelegate
# pragma mark Monitoring App State Changes
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Window and root VC set up in window getter
[self.window makeKeyAndVisible];
return YES;
}
# pragma mark Managing App State Restoration
- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder {
return YES;
}
- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder {
return YES;
}
#pragma mark Providing a Window for Storyboarding
- (UIWindow *)window {
if (!_window) {
_window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
_window.rootViewController = self.navigationController;
}
return _window;
}
- (FLNavigationController *)navigationController {
if (!_navigationController) {
FLPodcastTableViewController* podcastViewController = [[FLPodcastTableViewController alloc] initWithStyle:UITableViewStylePlain];
_navigationController = [[FLNavigationController alloc] initWithRootViewController:podcastViewController];
}
return _navigationController;
}
FLNavigationController.m
- (id)initWithRootViewController:(UIViewController *)rootViewController {
self = [super initWithRootViewController:rootViewController];
if (self) {
self.restorationIdentifier = #"FLNavigationController";
self.restorationClass = self.class;
}
return self;
}
#pragma mark - UIViewControllerRestoration
+ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder {
FLPodcastTableViewController* podcastViewController = [[FLPodcastTableViewController alloc] initWithStyle:UITableViewStylePlain];
return [[self alloc] initWithRootViewController:podcastViewController];
}
FLPodcastTableViewController.m
- (id)initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self) {
[self.tableView registerClass:FLPodcastTableViewCell.class forCellReuseIdentifier:FLPodcastTableViewCellIdentifier];
self.restorationIdentifier = #"FLPodcastTableViewController";
self.restorationClass = self.class;
}
return self;
}
#pragma mark - UIViewControllerRestoration
+ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder {
return [[self alloc] initWithStyle:UITableViewStylePlain];
}
FLPodcastEpisodeTableViewController.m
- (id)initWithPodcast:(FLPodcast *)podcast {
self = [self initWithStyle:UITableViewStylePlain];
if (self) {
self.podcast = podcast;
self.restorationIdentifier = #"FLPodcastEpisodeTableViewController";
self.restorationClass = self.class;
[self.tableView registerClass:FLPodcastEpisodeTableViewCell.class forCellReuseIdentifier:FLPodcastEpisodeTableViewCellIdentifier];
}
return self;
}
#pragma mark - UIViewControllerRestoration
+ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder {
FLPodcastEpisodeTableViewController* viewController = nil;
NSString* podcastURI = [coder decodeObjectForKey:kPodcastURLKey];
NSURL* podcastURL = [NSURL URLWithString:podcastURI];
FLPodcast* podcast = [FLPodcast podcastWithURL:podcastURL];
if (podcast) {
viewController = [[self alloc] initWithPodcast:podcast];
}
return viewController;
}
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
[coder encodeObject:self.podcast.feedURL.absoluteString forKey:#kPodcastURLKey];
[super encodeRestorableStateWithCoder:coder];
}
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder {
[super decodeRestorableStateWithCoder:coder];
}

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

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.

iOS 6 device orientation issue

I have 2 view controllers. I want 1st viewcontroller to be Portrait mode only while 2nd viewController should support all orientations. Please help me.
In AppDelegate class, my code is :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil] autorelease];
UINavigationController * navController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = self.viewController;
// [self.window addSubview:navController.view];
[self.window makeKeyAndVisible];
return YES;
}
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
NSLog(#"supportedInterfaceOrientationsForWindow");
return UIInterfaceOrientationMaskAllButUpsideDown;
}
1st ViewController code is:
-(BOOL)shouldAutorotate
{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
// Tell the system which initial orientation we want to have
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskPortrait;
}
2nd ViewController code is:
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
-(BOOL)shouldAutorotate
{
return YES;
}
// Tell the system which initial orientation we want to have
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
What i inspect is 'shouldAutorotate' method is not called for 1st and 2nd ViewController.
Your quick help will highly be appreciable.
Thanks.
Kashif
Try to set supportedInterfaceOrientations for 2nd UIViewController like this:
- (BOOL) shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight; // add any other you want
}
Also, enable only portrait in same method in 1st UIViewController.
Maybe you need to enable those orientations also in project settings which 2nd UIViewController needs to support.
[edit #1: Added sample application]
Here you go sample application which solves your problem, hopefully.
AppDelegate.h
#import <UIKit/UIKit.h>
#class FirstViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) FirstViewController *viewController;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "FirstViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController
- (IBAction)goToSecondViewController:(id)sender;
#end
FirstViewController.m
#import "FirstViewController.h"
#import "SecondViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(BOOL)shouldAutorotate
{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationMaskPortrait;
}
- (IBAction)goToSecondViewController:(id)sender
{
SecondViewController *svc = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self presentViewController:svc animated:NO completion:nil];
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
- (IBAction)goToFirstViewController:(id)sender;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
-(BOOL)shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
- (IBAction)goToFirstViewController:(id)sender
{
[self dismissViewControllerAnimated:NO completion:nil];
}
#end
FirstViewController.xib
SecondViewController.xib
As per your description , first view controller pushed into navigation controller. Your method definition of shouldAutorotate and supportedInterfaceOrientations are absolutely correct. During orientation changes, your navigation Controller's shouldRotate only fired and won't fired your first view controller's(child of nav controller) shouldAutorotate. So you have to category navigationController in your view controller or in seperate file and import into it wherever needed. Code as below for UINavigation Controller category.
.h file have this code
#interface UINavigationController (autoRotate)
-(BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;
#end
.m file have this code
#import "UINavigationController+autoRotate.h"
#implementation UINavigationController (autoRotate)
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
If you write category in separate file, you have to import .h file in your first and second view controllers as #import "UINavigationController+autoRotate"
a simple solution:
implement : - (NSUInteger)supportedInterfaceOrientations
when asked from AppDelegate.m
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
for more detail already answered here:
iOS 6 landscape and portrait orientation

Xcode 4 for Dummies: Why are Storyboard Settings not Being Applied When the App Runs?

SOLUTION
Make sure in the plist that the storyboard name is listed as the main storyboard file name.
I have a Storyboard with a UINavigationViewController that's connected to a NavigationViewController class and it's set as the UIWindow rootViewController. When the app runs (in the Simulator (5.1)) I get a blank black screen with the blue-ish navigation bar on the top.
The first problem is that in the storyboard, I set the navigation bar to black. I also set the status bar to translucent black. Neither styles are being honored when the app runs.
And the second problem is that the navigation controller's view is empty even though in the storyboard it has a relationship to a UITableViewController.
How can I fix both of these issues. I just started using Xcode again and had been using 4.0 before so the storyboards are throwing me off...
UPDATE
Here's the code as requested. Obviously I can't post the storyboard (can I?).
AppDelegate:
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize navigationController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
navigationController = [[NavigationViewController alloc] init];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
#end
NavigationViewController:
#import "NavigationViewController.h"
#interface NavigationViewController ()
#end
#implementation NavigationViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
The problem is that you are setting as the root controller a completely blank root controller, not the one from the story board. What you want to do is to delete that part of the code, and simply on the storyboard click the thing that says "is initial view controller"
When using storyboards you usually dont have to modify the appdelegate, because xcode sets which is the initial view that will appear and all of that based solely on how you set the storyboard. You can check this in the plist where it says which storyboard will be used as the main one.
If you want to load your navigation controller like that then you can do something like that you would have to get the viewcontroller from the storyboard itself and present it.
instantiateViewControllerWithIdentifier
but there is no need for that when using storyboards as it automatically loads whichever is set as the initial one (which can be seen as the viewcontroller with the arrow pointing at it)
Your app delegate method should look like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return YES;
}

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).

Resources