Load a .nib at first app launch - objective-c

I want to show the "intro" nib i made only at first app launch.
I was using the following code in my viewDidLoad but it seems to do nothing (even in ViewWillAppear). I tried to clean, remove the app from simulator and device and build again but nothing happened.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"firstRun"]){
IntroViewController *intro = [[IntroViewController alloc] initWithNibName:nil bundle:nil];
intro.modalTransitionStyle = UIModalTransitionStyleCoverVertical ;
[self presentModalViewController:intro animated:YES];
[intro release];
[defaults setObject:[NSDate date] forKey:#"firstRun"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
I also tried to show a little UIAlertView at first launch, and it works! Am i failing to load the nib?
EDIT
I forgot to say it's a tab Bar based app and i've some code in my app delegate to highlight rows at the first three sessions of the app.
Any help appreciated!

Ok, add the following code and it should work:
- (void)Loadview_afterdelay{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"firstRun"]){
IntroViewController *intro = [[IntroViewController alloc] initWithNibName:nil bundle:nil];
intro.modalTransitionStyle = UIModalTransitionStyleCoverVertical ;
[self presentModalViewController:intro animated:YES];
[intro release];
[defaults setObject:[NSDate date] forKey:#"firstRun"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void)viewDidLoad {
[self performSelector:#selector(Loadview_afterdelay) withObject:nil afterDelay:0.5];
}
Apparently, in this case, you can't load a second view right after your view is loaded (viewdidload)
Therefor you just set a small delay before loading your second view.

Try the following:
IntroViewController *intro = [[IntroViewController alloc] initWithNibName:#"IntroViewController" bundle:nil];
intro.modalTransitionStyle = UIModalTransitionStyleCoverVertical ;
[self presentModalViewController:intro animated:YES];
[intro release];
I have added your .nib name to initWithNibName
Also, if you're using iOS 5 (and ARC), you should use this:
IntroViewController *intro = [[IntroViewController alloc] initWithNibName:#"IntroViewController" bundle:nil];
intro.modalTransitionStyle = UIModalTransitionStyleCoverVertical ;
[self presentModalViewController:intro animated:YES completion:nil];

Have you tried moving it to viewDidAppear?

It looks to me that you should place that code in your AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Modify the code above to what you need.
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
[application setStatusBarHidden:YES withAnimation:NO];
return YES;
}
It is there that your telling your application what view to start with.
So first time have a firstTimeViewController.
If you are doing it here don't animate the transition in.
Just animate the transition off.
Put a break point and check if you are going into the viewDidLoad method and if so check if your test is appropriate.
I suggest maybe using a BOOL in an NSNumber to check agains.
On top of that you may consider the option to put that in viewDidAppear.

As #Louis already answered the question very well already the only thing is It's just not compatible with the ARC since there are a [ release] What I'll write now isn't new but I'll declare it more for the beginner ones.
First you have to import the TourGuideViewController.h in your RootViewController.h which will be like similarly like this:
#import <UIKit/UIKit.h>
#import "TourGuideViewController.h"
#interface RootViewController : UITabBarController
{
TourGuideViewController *TourGuideViewController;
}
#property (nonatomic, strong) TourGuideViewController *TourGuideViewController;
#end
Then You have to synthesize and implement your function in your RootViewController.m file:
#import "RootViewController.h"
#interface RootViewController ()
#end
#implementation RootViewController
#synthesize TourGuideViewController = _TourGuideViewController;
- (void)viewDidLoad
{
[self performSelector:#selector(LoadTourGuide) withObject:nil afterDelay:0.5];
}
- (void)LoadTourGuide{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"FirstRun"]){
TourGuideViewController *TourGuideVC = [self.storyboard instantiateViewControllerWithIdentifier:#"TourGuideViewController"];
TourGuideVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:TourGuideVC animated:YES completion:NULL];
[defaults setObject:[NSDate date] forKey:#"FirstRun"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
}
#end

Related

Objective C - When tapping the tab bar item again, how to reload web view again?

I really need help please. Initially, by tapping on a tab bar item, I will load a webview on Gym VC user will then scroll down the web view
What I am trying to accomplish is when user tap on the same tab bar item again, the webView will reload again. I managed to call the method handleRefresh from MyTabBarController But the method doesn't do anything at all. Any guidance is much appreciated.
Currently I have the following code
MyTabBarController.m
#import "GymNavigationController.h"
#import "Gym.h"
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
if([viewController isKindOfClass:[GymNavigationController class]]){
Gym *myGym = [[Gym alloc] init];
[myGym handleRefresh:nil];
}
}
Gym.m
#import "Gym.h"
#import "AppDelegate.h"
#import "GymDet.h"
#import <QuartzCore/QuartzCore.h>
#interface Gym () {
AppDelegate *appDelegate;
NSString *sURL, *sRefresh;
}
#end
#implementation Gym
#synthesize webView;
- (void)viewDidLoad {
[super viewDidLoad];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
sURL = appDelegate.gURL;
sURL = [sURL stringByAppendingString:#"/apps/gym.asp?"];
NSLog(#" The sURL to be load for the current page : %# ", sURL);
sRefresh = sURL;
[defaults setObject:sRefresh forKey:#"txtRefresh"];
[defaults synchronize];
NSURL *url = [NSURL URLWithString:sURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView setDelegate:(id<UIWebViewDelegate>)self];
[webView loadRequest:urlRequest];
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[webView.scrollView addSubview:refreshControl];
}
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
//[self handleRefresh:nil];
[[self navigationController] setNavigationBarHidden:YES animated:YES];
}
-(void)viewDidDisappear:(BOOL)animated{
[[self navigationController] setNavigationBarHidden:NO animated:YES];
}
- (void)handleRefresh:(UIRefreshControl *)refresh {
//--- Call the stored txtMemCode, something like session ---
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
sRefresh = [defaults objectForKey:#"txtRefresh"];
NSURL *url = [NSURL URLWithString:sRefresh];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView loadRequest:urlRequest];
[refresh endRefreshing];
}
First i would like to suggest why you're initiating a new Gym object every time tabbar is tapped you should take a reference of the Gym object and initialise it if its nil then process ahead with the reference, but it maybe your requirement and if it is i would like to suggest you to create a BOOL variable lets say isUpdateRequire and when you're instantiating your viewcontroller assign isUpdateRequire = true. Then in the end of view did load or view will appear (according to your need) check
if isUpdateRequire {
[self handleRefresh:nil]
}
Alternatively you can create protocols in your webviewcontroller and assign its delegate to your tabbarcontroller and fire the delegate method when ever required.
and if you don't want the method to call when you come back to vc simply put this condition in viewWillAppear
if self.isMovingToParentViewController {
[self handleRefresh:nil]
}

I want to stay on logout page, when application runs again (if user did not hit logout button)

Below is my code till sign in process
#import "ViewController.h"
#import "LogOutViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *userid = [defaults objectForKey:#"uid"];
NSString *password = [defaults objectForKey:#"pswrd"];
_lbluserid.text = userid;
_lblpswrd.text = password;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)btnsignin:(id)sender
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:_lbluserid.text forKey:#"uid"];
[defaults setObject: _lblpswrd.text forKey:#"pswrd"];
[defaults synchronize];
NSLog(#"Credentials are saved");
LogOutViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"logoutvc"];
controller.getUserid = _lbluserid.text;
[self.navigationController pushViewController:controller animated:YES];
}
#end
I have another view which will appear by signing in, on that view I have Log Out button, Now what I want is if user didn't hit logout button the same page (log out page) will be displayed when I run my app again.
Please help me..
try amend you code to.
#import "ViewController.h"
#import "LogOutViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *userid = [defaults objectForKey:#"uid"];
NSString *password = [defaults objectForKey:#"pswrd"];
_lbluserid.text = userid;
_lblpswrd.text = password;
if([defaults boolForKey:#"logedIn"]){
[self moveToLogoutViewController];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)btnsignin:(id)sender
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:_lbluserid.text forKey:#"uid"];
[defaults setObject: _lblpswrd.text forKey:#"pswrd"];
[defaults setBool: YES forKey:#"logedIn"];
[defaults synchronize];
NSLog(#"Credentials are saved");
[self moveToLogoutViewController];
}
- (void) moveToLogoutViewController{
LogOutViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"logoutvc"];
controller.getUserid = _lbluserid.text;
[self.navigationController pushViewController:controller animated:YES];
}
#end
You can try like this
First Open AppDelegate class in didFinishLaunchingWithOptions method.
Check user is exist or not by using NSUserDefaults.If user exist you can show LogOutViewController
Use keychain to store user credentials. In your viewCOntroller class, in viewDidLoad check if user credentials exist or not.If exist, then call:
LogOutViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"logoutvc"];
controller.getUserid = //get user id from keychain;
[self.navigationController pushViewController:controller animated:YES];

Switch Between 2 UIViewControllers in a NavigationBar Underneath

I have built a UIViewController to contain two other UIViewControllers. What I would like to do using a UISegment in the UINavigationBar is to switch between both views. When the user is finished they click on "Done" and it goes back to the RootViewController. I got this to work except the UIViewControllers take the size of the whole screen so the top portion is covered by the UINavigationBar. They don't adjust to the space under the UINavigationBar. I have been trying different techniques without success.
I have already tried in the ChildUIViewControllers without success
self.edgesForExtendedLayout = UIRectEdgeNone;
Here is my code:
RootViewController Calls the Container
ContainerController *controller = [[ContainerController alloc] init]
[self.navigationController pushViewController:controller animated:YES];
Container Code
- (void)viewDidLoad {
[super viewDidLoad];
UIViewController *vc = [self getCurrentViewController]; // Returns Current ViewController to Display
[self addChildViewController:vc];
vc.view.frame = self.view.bounds;
[self.view addSubview:vc.view];
self.currentViewController = vc;
}
-(UIViewController *)getCurrentViewController{
UIViewController *vc;
switch ([[NSUserDefaults standardUserDefaults] integerForKey:#"currentView"]) {
case kView1:{
vc = (ViewController1 *)[[ViewController1 alloc] init];
}break;
case kView2:{
vc = (ViewController2 *)[[ViewController2 alloc] init];
}break;
}
return vc;
}
- (void)segmentedControlIndexChanged:(id)sender{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[NSNumber numberWithInt:[sender selectedSegmentIndex]] forKey:#"currentView"];
[userDefaults synchronize];
UIViewController *vc = [self getCurrentViewController];
[self addChildViewController:vc];
[self transitionFromViewController:self.currentViewController toViewController:vc duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[self.currentViewController.view removeFromSuperview];
vc.view.frame = self.view.bounds;
[self.view addSubview:vc.view];
} completion:^(BOOL finished) {
[vc didMoveToParentViewController:self];
[self.currentViewController removeFromParentViewController];
self.currentViewController = vc;
}];
self.navigationItem.title = vc.title;
}
Anybody know what the problem is? Thanks.
I found a solution. The reason that the tableview was under the navigationbar was due to the translucence of the navigation bar. When I set this:
self.navigationController.navigationBar.translucent = NO;
The views remained under the navigation bar. There was still a black bar above the UITableView I fixed that problem by instead of using a UITableViewController I user a UIViewController and added a tableView. Here is some code to make cycle between the two views in the container uiviewcontroller:
- (void)viewDidLoad {
self.viewController1 = [[ViewController1 alloc] init];
self.viewController2= [[ViewController2 alloc] init];
switch ([[NSUserDefaults standardUserDefaults] integerForKey:#"dataView"]) {
case kDataView:{
self.viewController1.view.hidden=YES;
self.viewController2.view.hidden=NO;
}break;
case kChartView:{
self.viewController1.view.hidden=NO;
self.viewController2.view.hidden=YES;
}break;
}
[self.view addSubview:self.viewController1.view];
[self.view addSubview:self.viewController2.view];
}
- (void)segmentedControlIndexChanged:(id)sender{
if ([[NSUserDefaults standardUserDefaults] integerForKey:#"dataView"]!=[sender selectedSegmentIndex]){
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[NSNumber numberWithInteger:[sender selectedSegmentIndex]] forKey:#"dataView"];
[userDefaults synchronize];
self.segmentedControl.selectedSegmentIndex=[[NSUserDefaults standardUserDefaults] integerForKey:#"dataView"];
switch (self.segmentedControl.selectedSegmentIndex) {
case kDataView:{
self.viewController1.view.hidden=YES;
self.viewController2.view.hidden=NO;
}break;
case kChartView:{
self.viewController1.view.hidden=NO;
self.viewController2.view.hidden=YES;
}break;
}
}
}

How to solve NSViewController/ NSView error in connect the action with target?

I have some Default NSViewController. In it I have code:
- (void)viewDidLoad {
// Do view setup here.
NSUserDefaults *defaults = [[NSUserDefaults alloc] init];
if(![defaults boolForKey:#"isLoggedIn"]){
NSLog(#"Not logged in... Loading settings");
NSViewController *settings = [[NSViewController alloc] initWithNibName:#"Settings" bundle:nil];
[self.view addSubview:settings.view];
}
else{
NSLog(#"Logged in... Loading inbox");
NSViewController *inbox = [[NSViewController alloc] initWithNibName:#"Inbox" bundle:nil];
[self.view addSubview:inbox.view];
}
[super viewDidLoad];
}
That code works it loads view depends on that NSUserDefaults.
But when try to declare something in lets say Inbox.m/Inbox.h I am geting this error:
Could not connect the action testView: to target of class NSViewController
In Inbox.m I have:
- (void)viewDidLoad {
NSLog(#"Inbox loaded.");
[super viewDidLoad];
// Do view setup here.
}
And that NSLog is never executed. I want to have several nibs and different NSViewController connected to it.
My guess is that I am adding subviews wrong way. It is like visual elements are there and nothing else.
I solve this by:
Inbox *inbox = [[Inbox alloc] initWithNibName:#"Inbox" bundle:nil];
_viewController = inbox;
//Where _viewController is
NSViewController *_viewController;
//defined in
#interface Default : NSViewController{
NSViewController *_viewController;
}
Now everything works ok.

Instance variables not working in ViewController in UINavigationController

I'm still new to iOS development but I've ran into a problem that I can't solve and I've tried looking online but can't find anything yet.
I'm using a UIImagePickerController to pick and image and I'm using it in the App Delegate. When an image is returned, in the imagePickerController:didFinishPickingMediaWithInfo method, I want to make a new navigation controller with a view controller and put it over the "app".
Here is how I'm doing it:
CustomNavigationController *customNavigationController = [[CustomNavigationController alloc] init];
PhotoViewController *photoViewController = [[PhotoViewController alloc] initWithNibName:#"PhotoViewController" bundle:[NSBundle mainBundle]];
[customNavigationController pushViewController:photoViewController animated:NO];
[customNavigationController.view setFrame:[[UIScreen mainScreen] applicationFrame]];
[photoViewController release];
[self.window addSubview:customNavigationController.view];
//Call method of photoViewController.
[[customNavigationController.viewControllers objectAtIndex:0] addPhotoFromData:info];
[self.tabBarController dismissViewControllerAnimated:YES completion:nil]; //Get rid of UIImagePickerController
However in the photoViewController, I don't have access to any instance variables synthesized and loaded in viewDidLoad. They all return to null. There is also a tableView and calls to reload the tableView do not actually cause the tableView to respond.
Here is some of the code from photoViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.photoCount = 0;
self.timestamp = [[NSDate date] timeIntervalSince1970];
self.photos = [[NSMutableArray alloc] initWithCapacity:5];
self.photosData = [[NSMutableArray alloc] initWithCapacity:5];
self.uploadingCount = 0;
UINib *customCell = [UINib nibWithNibName:#"CustomTableCell" bundle:[NSBundle mainBundle]];
[self.tableView registerNib:customCell forCellReuseIdentifier:#"customCell"];
self.tableView.separatorColor = [UIColor clearColor];
NSLog(#"%#", self);
}
and also the addPhotoFromData method:
- (void)addPhotoFromData:(NSDictionary *)info
{
[self.photos addObject:info];
NSLog(#"%#", self.photos); //Doesn't add "info" and does not return anything when later called from other methods.
[self.tableView reloadData]; //Doesn't work
Everything was working before I add in the UINavigationController. I'm completely lost.
EDIT: After some more debugging attempts, I have discovered that the view is not loaded when addPhotoFromData is called. viewDidLoad is called afterwords. Is there a way to delay method calls?
Any reason you can't have the PhotoViewController call addPhotoFromData: inside the viewDidLoad method? You can always access properties of the app delegate from the view controller:
YourAppDelegateType * delegate = [UIApplication sharedApplication].delegate;
[self addPhotoFromData:delegate.info];