facebook log in - ios

I'm working on integrating a facebook connect to my application and I have 2 problems:
1.
LBLoginViewController is the view that presents as the app launches.
I want to use the storyboard to put some ui elements but for some reason that I don't understand I cannot do that manually, only in code. How can I use the custom class LBLoginViewController?
2.
after the log in success I manage to load a view controller. I wont to load a UITabBarController but the method I'm using cannot do that. Which method can I use to do so?
this is the code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
// the view controller that load after log in
ListOfJobs *rootViewController =
[[ListOfJobs alloc] init];
UINavigationController *navController =
[[UINavigationController alloc]initWithRootViewController:rootViewController];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
// if the user logs in, do nothing - the root view is already up
if (FBSession.activeSession.state
== FBSessionStateCreatedTokenLoaded) {
NSLog(#"User Logged In");
}
//create and present the login view controller
else {
LBLoginViewController *loginViewController =
[[LBLoginViewController alloc] init];
[rootViewController presentViewController:
loginViewController animated:NO completion:nil];
}
return YES;
}

You should be able to add a UIViewController to your storyboard and then set its class to LBLoginViewController using the identity inspector.

What I think you should do for 2 is to assign your TabBarController as your root view controller
self.window.rootViewController = self.tabBarController;
and open LBLoginViewController as a modal view at the end of didFinishLaunchingWithOptions.
You can always check first if your user has already authorized your app with something like this:
if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) {
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
} else {
//open login view
}

Related

Logging off ios app and returning to RootViewController

I created a RootViewController in my app delegate like so:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
StartViewController *viewController = [[StartViewController alloc] init];
StartNavigationController *navigationController=[[StartNavigationController alloc] initWithRootViewController:viewController];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
}
When I hit the logout button, I want to send the user back to the rootview controller:
- (IBAction) logoutButtonPressed:(UIButton *)sender
{
[Users logOut];
[self.navigationController popToRootViewControllerAnimated:YES];
}
This works fine when I run it on my iPhone 4s (testing iphone 6 when it arrives), but if I leave the user logged in for more than a day and click the logout button, the screen slides to black.
Why is my root view controller not calling my startviewcontroller after like 24 hours or so?
I am trying to put an answer, I guess it should work for you. First you check for StartViewController whether it exist in navigationController stack or, not. As per your stack StartViewController should be your first controller added in navigationController.
StartViewController *loginController=[self.navigationController.viewControllers objectAtIndex:0];
if(loginController){
[self.navigationController popToViewController:loginController animated:YES];
}else{
NSMutableArray *controllers=[[NSMutableArray alloc] init];
loginController=[[StartViewController alloc] initWithNibName:#"StartViewController" bundle:nil];
[controllers addObject:loginController];
[controllers addObjectsFromArray:self.navigationController.viewControllers];
self.navigationController.viewControllers=[[NSArray alloc] initWithArray:controllers];
[self.navigationController popToRootViewControllerAnimated:YES];
}
I think it should work.
Cheers.

Facebook iOS SDK, Logout (CloseAndClearTokenInformation) not working?

I've set up the Facebook iOS SDK with my app, and everything works fine. I can login using Facebook, but for some reason when I try and click my "Logout" button (top right, see image below), it doesn't do anything. I'm using a Storyboard to create my app (the login xib opens on top of my existing storyboard), and everything in my AppDelegate seems correct. What am I missing? See snippets of code below.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.mainViewController = [[SSViewController alloc]
initWithNibName:#"SSViewController" bundle:nil];
self.navController = [[UINavigationController alloc]
initWithRootViewController:self.mainViewController];
self.window.rootViewController = self.navController;
[self.window makeKeyAndVisible];
if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) {
// Yes, so just open the session (this won't display any UX).
[self openSession];
} else {
// No, display the login page.
[self showLoginView];
}
return YES;
}
- (void)showLoginView
{
UIViewController *topViewController = [self.navController topViewController];
UIViewController *modalViewController = [topViewController modalViewController];
// If the login screen is not already displayed, display it. If the login screen is
// displayed, then getting back here means the login in progress did not successfully
// complete. In that case, notify the login view so it can update its UI appropriately.
if (![modalViewController isKindOfClass:[SSLoginViewController class]]) {
SSLoginViewController* loginViewController = [[SSLoginViewController alloc]
initWithNibName:#"SSLoginViewController"
bundle:nil];
[topViewController presentViewController:loginViewController animated:NO completion:nil];
} else {
SSLoginViewController* loginViewController =
(SSLoginViewController*)modalViewController;
[loginViewController loginFailed];
}
}
SSViewController.m
-(void)logoutButtonWasPressed:(id)sender {
[FBSession.activeSession closeAndClearTokenInformation];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
initWithTitle:#"Logout"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(logoutButtonWasPressed:)];

Changing root view controller after iOS app has loaded.

In order to show my login screen when the app loads, and not after the user logs in, I have decided to add an auth object in NSUserDefaults when the user logs in successfully. When the app is launched that auth parameter is checked, and the view controller is set accordingly (if the user is auth it'll show a feed, if not it'll show a login screen) In the latter case, I have the app delegate reset the root view controller to the feed after the user has logged in. Is this bad practice or is there a better way of doing this?
In the app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
IIViewDeckController* deckController = [self generateControllerStack];
self.rightController = deckController.rightController;
self.centerController = deckController.centerController;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([[defaults objectForKey:#"auth"] isEqualToNumber:[NSNumber numberWithInt:1]]){
self.window.rootViewController = deckController;
}else{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle:nil];
UIViewController* vc = [sb instantiateViewControllerWithIdentifier:#"loginViewController"];
self.window.rootViewController = vc;
}
[self.window makeKeyAndVisible];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];
return YES;
}
- (void) setRoots
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
IIViewDeckController* deckController = [self generateControllerStack];
self.rightController = deckController.rightController;
self.centerController = deckController.centerController;
self.window.rootViewController = deckController;
[self.window makeKeyAndVisible];
}
In the login view controller:
- (IBAction)loginClick:(id)sender {
if([_emailField.text length]>0&&[_passField.text length]>0){
NSString *user = _emailField.text;
NSString *pass = _passField.text;
[[API sharedInstance] login:user andPass:pass onCompletion:^(NSDictionary *json){
NSLog(#"%#", json);
if(![json objectForKey:#"error"]){
[API sharedInstance].authorized = 1;
NSNumber *auth = [NSNumber numberWithInt:1];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:auth forKey:#"auth"];
[defaults synchronize];
captureYouAppDelegate *app = [[UIApplication sharedApplication] delegate];
[app setRoots];
}else{
[API sharedInstance].authorized = 0;
}
}];
}else{
if([_emailField.text length]<1){
[_emailField becomeFirstResponder];
}else{
[_passField becomeFirstResponder];
}
}
}
I'm wondering if there is a better or easier way than doing that. Thank you!
Just to clarify. I had reset UIWindow's rootViewController before without any problem but when attempting to do so while allowing device rotation I ran into some issues — Rotation just stopped working.
I found the following directly from Apple's docs while trying to debug. The link below has a number of guidelines about working with UIWindow. These are all related to device rotation but still good to know.
Short answer, use a root controller and add child view controllers. You can then swap out the child VCs with no problem.
• You have added your view controller's UIView property to UIWindow as a subview.
Developers are discouraged from adding the view property of any view controller as a subview of UIWindow. Your application's root view controller should be assigned to the app window's rootViewController property either in Interface Builder, or at runtime before returning from application:didFinishLaunchingWithOptions:. If you need to display content from more than one view controller simultaneously, you should define your own container view controller and use it as the root view controller. See Creating Custom Container View Controllers.
Check this technical Q&A for more details.
I don't think reset the window.rootViewController is a bad practice. However, there is no need to recreate a window.
If you don't want to use the previous view controller, just replace the window's rootViewController with the new view controller. If you do want to switch back to your previous view controller, use -presentViewController: animated: completion: to present your view controller may be a better alternative.
There is no need to alloc window again you can directly set this
window.rootViewController = yourVC;
Step By Step i am showing the Good Practice to use of rootviewcontroller with the help of UINavigationController
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.splash = [[SplashViewController alloc] initWithNibName: #"SplashViewController" bundle: nil];
self.window.rootViewController = self.splash;
[self.window makeKeyAndVisible];
DLog(#"finished initializing .....");
[self setRootViewController];
return YES;
}
- (void) setRootViewController
{
DLog(#"setRootViewController");
if (self.sessionManager.isLoggedIn)
{
[self navigateToHomeController];
} else {
[self navigateToLoginController];
}
}
- (void) navigateToHomeController
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"kStoryBoard" bundle: nil];
UINavigationController* homeNavigationController = [storyboard instantiateViewControllerWithIdentifier:#"kHomeNavController"];
NSArray* controllers = [homeNavigationController viewControllers];
if([controllers lastObject])
{
if ([[controllers objectAtIndex:0] isKindOfClass:[HomeViewController class]]) {
HomeViewController* homeController = (HomeViewController*) [controllers objectAtIndex:0];
self.window.rootViewController = [[OLNavigationViewController alloc] initWithRootViewController: homeController];
}
}
}
- (void) navigateToLoginController
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"kStoryBoard" bundle: nil];
UINavigationController* loginNavigationController = [storyboard instantiateViewControllerWithIdentifier:#"kLoginNavController"];
if ([loginNavigationController isKindOfClass:[OLLoginViewController class]]) {
OLLoginViewController* loginController = (OLLoginViewController*) loginNavigationController;
loginController.shouldHideToolBar = YES;
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController: loginController];
}
}

iOS Login Modal

I'm writing an iOS application which I need to have the user login to. The login will need to make a JSON request to a web service, then store the user details in Core Data or wherever is best.
Further, I need to have the login modal appear before the main application kicks in, I know that for this I call it in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions.
So, I need a simple login, username and password field, make a request and then store the resulting JSON data into somewhere, core data perhaps?
I've searched high and low for a login example, but they're all very rudimentary or not doing quite what I want. I'm thinking of creating a xib file then calling that, but I'm unsure about it all.
I was wondering the same question several days ago.
Here is my solution:
in didFinishLaunchingWithOptions ,I invoke a method check whether there is account and password in your database(core data? i just use the userdefault).
If there is , try login, if login fail, present a modal view. if successed, set your appdelegate.window.rootviewcontroller the main viewcontroller
If there is nothing, show modal view.
or login failed, blablabla...
sorry for my poor English.
here is my code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
UINavigationController *nav = [[UINavigationController alloc] init];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
[ZTCAPIClient registerUserInfo];
return YES;
}
+ (void) registerUserInfo {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *account = [defaults stringForKey:#"account"];
if(!account) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// load default value
[self performSelector:#selector(registerDefaultsFromSettingsBundle)];
dispatch_async(dispatch_get_main_queue(), ^{
ZTCUserSettingsViewController *userSettingsView = [[ZTCUserSettingsViewController alloc] init];
UINavigationController *usersSettingsNav = [[UINavigationController alloc] initWithRootViewController:userSettingsView];
[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentModalViewController:usersSettingsNav animated:NO];
[ZTCNotice showSuccessNoticeInView:userSettingsView.view title:[NSString stringWithFormat:#"%#,%#",NSLocalizedString(#"login first time use title", nil),NSLocalizedString(#"login first time use message", nil)]];//TODO
});
});
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if ([ZTCAPIClient loginWithAccount:[defaults stringForKey:#"account"] Password:[defaults stringForKey:#"password"] BaseURL:[defaults stringForKey:#"url"]]) {
//DLog(#"Log in SUCCESS");
dispatch_async(dispatch_get_main_queue(), ^{
UITableViewController *viewController = [[ZTCTaskListViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:viewController];
[[[[UIApplication sharedApplication] delegate] window] setRootViewController:nav];
});
} else {
//DLog(#"Log in FAIL");
dispatch_async(dispatch_get_main_queue(), ^{
ZTCUserSettingsViewController *userSettingsView = [[ZTCUserSettingsViewController alloc] init];
UINavigationController *usersSettingsNav = [[UINavigationController alloc] initWithRootViewController:userSettingsView];
[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentModalViewController:usersSettingsNav animated:NO];
[ZTCNotice showErrorNoticeInView:userSettingsView.view title:NSLocalizedString(#"login fail title", nil) message:NSLocalizedString(#"login fail message", nil)];
});
}
});
}
}
Just make didFinishLaunchingWithOptions modally push your LoginViewController to the navigation stack. If you're using a storyboard, you can just make your LoginViewController the root view controller, or alternatively place a segue, give it an identifier, and just call [rootViewController performSegueWithIdentifier:#"YourSegueId" sender:self].

How to presentModalViewController in applicationDidFinishLaunching?

Here is my situation:
I have a TaskListViewController(UITableView) which need Internet.
So I used AFNetworking to do some login work(with demo account and password) before the TaskList is showed.
Now I need to let the user set their account and password.
So I just want to present a Modal View(ZTCUserSettingsViewController) before login.
And I cost a lot time, it still doesn't work.
Is there any way to solve this?
Thank you.
ZTCAPIClient : AFHTTPClient
ZTCTaskListViewController : UITableViewController
code
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
[ZTCAPIClient login];
UITableViewController *viewController = [[ZTCTaskListViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:viewController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}
I don't see where your sample code attempts to present the modal view controller. Perhaps it happens inside of -[ZTCAPIClient login].
Generally speaking, you can't present a modal view controller until after the presenting view controller's view is in the view hierarchy. For your specific question, this means your program needs to present the modal sometime after the line that reads [self.window makeKeyAndVisible];. It will not work if your program tries to present the modal view controller before, in fact, you'll probably see an error message logged to the debug console.
On a side note, you should be careful not to make your program do too much in -application:didFinishLaunchingWithOptions:. If your program takes too long, the system may kill your app the iOS App Programming Guide states:
Your application:willFinishLaunchingWithOptions: and
application:didFinishLaunchingWithOptions: methods should always be as
lightweight as possible to reduce your app’s launch time. Apps are
expected to launch and initialize themselves and start handling events
in less than 5 seconds. If an app does not finish its launch cycle in
a timely manner, the system kills it for being unresponsive. Thus, any
tasks that might slow down your launch (such as accessing the network)
should be executed asynchronously on a secondary thread.
When launching into the foreground, the system also calls the
applicationDidBecomeActive: method to finish the transition to the
foreground. Because this method is called both at launch time and when
transitioning from the background, use it to perform any tasks that
are common to the two transitions.
Here is my final solution:
launch up:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
UINavigationController *nav = [[UINavigationController alloc] init];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
//important!
[ZTCAPIClient registerUserInfo];
return YES;
}
in ZTCAPIClient.m:
+ (void) registerUserInfo {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *account = [defaults stringForKey:#"account"];
if(!account) {
// load default value
[self performSelector:#selector(registerDefaultsFromSettingsBundle)];
ZTCUserSettingsViewController *userSettingsView = [[ZTCUserSettingsViewController alloc] init];
UINavigationController *usersSettingsNav = [[UINavigationController alloc] initWithRootViewController:userSettingsView];
[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentModalViewController:usersSettingsNav animated:NO];
} else {
DLog(#"**********************");
if ([ZTCAPIClient loginWithAccount:[defaults stringForKey:#"account"] Password:[defaults stringForKey:#"password"] Mode:[defaults stringForKey:#"requestType"] BaseURL:[defaults stringForKey:#"url"]]) {
DLog(#"Log in SUCCESS");
UITableViewController *viewController = [[ZTCTaskListViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:viewController];
[[[[UIApplication sharedApplication] delegate] window] setRootViewController:nav];
} else {
DLog(#"Log in FAIL");
ZTCUserSettingsViewController *userSettingsView = [[ZTCUserSettingsViewController alloc] init];
UINavigationController *usersSettingsNav = [[UINavigationController alloc] initWithRootViewController:userSettingsView];
[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentModalViewController:usersSettingsNav animated:NO];
}
}
}

Resources