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:)];
Related
I had a requirement to cover the screen with black layout when the user moves the application to the background applicationDidEnterBackground in order to maintain the privacy of some sensitive datas on the screen. So for this i made use of AppDelegate function to present with a black color in background and then remove that by dismissing it when comes to foreground applicationDidEnterBackground. The code is:
#import "AppDelegate.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIViewController *blankViewController = [UIViewController new];
blankViewController.view.backgroundColor = [UIColor blackColor];
[self.window makeKeyAndVisible];
[self.window.rootViewController presentViewController:blankViewController animated:NO completion:NULL];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[self.window.rootViewController dismissViewControllerAnimated:false completion:nil];
}
#end
Now in my application everything is working fine but in one screen i am presenting a ViewContollerB on a button click by using : [self presentViewController:webview animated:YES completion:nil]; The application as usually gets covered with black color when moving to background but when i take the application to foreground after this, then the presented ViewContollerB also gets dismissed . How to prevent my presented ViewController to get dismissed once coming from background?
Create a new 'UIViewController' called OverLayViewController and load it in
applicationDidEnterBackground method
- (void)applicationDidEnterBackground:(UIApplication *)application {
OverLayViewController *blankViewController = [OverLayViewController new];
blankViewController.view.backgroundColor = [UIColor blackColor];
[self.window makeKeyAndVisible];
UIViewController *rvc = self.window.rootViewController;
UIViewController *pvc = rvc.presentedViewController; // you may need to loop through presentedViewControllers if you have more than one
if(pvc != nil) {
[pvc presentViewController: blankViewController animated: NO completion:nil];
}
else{
[self.window.rootViewController presentViewController: blankViewController animated: NO completion:nil];
}
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
UIViewController *test = [self topViewController];
if ([test isKindOfClass:[OverLayViewController class]]) {
[test dismissViewControllerAnimated:false completion:nil];
}
}
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
-(UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
In this case, dismissViewContoller code wont apply for your webview.
You are trying to do the following: rootviewcontroller A presents a blank viewcontroller B. Your app goes into background, and you present viewcontroller C from there. Now B closes as A is presenting both B and C, and that is not allowed.
You will need to check if your rootviewcontroller is presenting any viewcontrollers, and if those are presenting any others recursively. You can check for those by using the property presentedViewController on a viewcontroller.
Personally, I would (in a base viewcontroller class that all viewcontrollers inherit from) keep a variable that checks if this one is visible (by keeping track of viewDidAppear and viewDidDisappear). If this is the one that is visible, you add a blank view on top.
Answer in Swift because I can't be trusted with Objective-C without an editor:
class BaseViewController: UIViewController {
var appeared = false
func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated: animated)
appeared = true
}
func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated: animated)
appeared = false
}
}
Then you need to fire a notification from the AppDelegate that is caught in this viewcontroller, and then show a blank view on top.
I am using SWRevealViewController for Slide Out Menu for an application in which slide out menu starts only from the Home Screen after Sign Up button is pressed in SignUp page(i.e. running the application for the first time).
When the app is running for the second time it is suppose to go directly to the Home Screen,but the app is crashing, and I am getting crash log in ViewController.
_barBtnMenu.target = self.revealViewController;
_barBtnMenu.action = #selector(revealToggle:);
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
NSInvalidArgumentException', reason:'-[__NSArrayM
insertObject:atIndex:]: object cannot be nil.
For app's first time run I am using Present Modally Segue from Sign Up button.
In SWRevealViewController
- (SWRevealViewController*)revealViewController
{
UIViewController *parent = self;
Class revealClass = [SWRevealViewController class];
while ( nil != (parent = [parent parentViewController]) && ![parent isKindOfClass:revealClass] ) {}
return (id)parent;
}
While running it for the first time
parent is returning a value but for the second run it is returning nil
If anyone could help me in solving the issue.
Thanks in advance.
EDIT
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"email"];
if (savedValue != nil) {
UIStoryboard *storyboard = self.window.rootViewController.storyboard;
ViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"viewController"];
self.window.rootViewController =viewController;
[self.window makeKeyAndVisible];
} else {
NSLog(#"Sign Up screen opened");
}
return YES;
}
You are trying to implement Autologin feature in your app
for the second launch you have to maintain a flag in Appdelegate that user is already logged in or not , if user is already logged in you have to move to the parent controller of SWRevealview from didfinishlaunchingwithoptions function in app delegate.
for that save username and password to userdefaults at login & signup
check for values in didfinishlaunchingwithoptions
if value exist move to parent of SWrevealview
Thanks for the replies,
I solved it by making SignUp page as Root view
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"email"];
if (savedValue == nil) {
UIStoryboard *storyboard = self.window.rootViewController.storyboard;
SignUpViewController *signUpViewController = [storyboard instantiateViewControllerWithIdentifier:#"signUpViewController"];
self.window.rootViewController = signUpViewController;
[self.window makeKeyAndVisible];
} else {
NSLog(#"Sign Up screen closed,Hom page opened");
}
return YES;
}
Where is best place to put login fork for IOS app?
I've seen it suggested to place it in appdelegate. However, I'm wondering if this creates unneeded overhead, doesn't always get triggered or, in general, if there might be a better option.
Is putting it in applicationdidFinishLaunchingWithOptions best place for it as in following or should it be somewhere else?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if(![[NSUserDefaults standardUserDefaults] boolForKey:#"loggedin"]) {
// go to login screen
NSLog(#"not logged in");
[self presentWelcomeInterface];
} else {
// go to main screen
NSLog(#"logged in");
[self presentMainInterface];
}
- (void)presentMainInterface
{
self.window.rootViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]] instantiateInitialViewController];
}
- (void)presentWelcomeInterface
{
UIViewController* rootController = [[UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:#"login"];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:rootController];
self.window.rootViewController = navigation;
}
The approach I use is to have a root view controller which decides which segue to perform depending on the login status:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if([UserDefaultsUtility onboardingComplete]){
[self performSegueWithIdentifier:ShowMainScreenSegue sender:self];
}else{
[self performSegueWithIdentifier:ShowOnboardingSegue sender:self];
}
}
By using this approach you partition the code nicely for better maintainability.
As a bonus, this root view controller could have the launch image as it's content:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.layer.contents = (id) [UIImage imageNamed:[self activeLaunchImage]].CGImage;
}
- (NSString *) activeLaunchImage
{
NSString *launchImage;
if ((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) &&
([UIScreen mainScreen].bounds.size.height > 480.0f)) {
launchImage = #"LaunchImage-700-568h";
} else {
launchImage = #"LaunchImage-700";
}
return launchImage;
}
By doing this, the user won't even notice the root view controller as the transition will be done seamlessly towards the right place depending on the login status.
P.S: The active launch image method needs to be modified if you want to get the specific launch image for the two iPhone 6.
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
}
I want to display interface UITabBar when login succeeds.
I declare interface UITabBar in AppDelegate, but after login success I don't know how to call the interface.
Here is my code:
appdelegate.m
-(void)loadInterface
{
[self configureiPhoneTabBar];
}
-(void)configureiPhoneTabBar
{
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
UIViewController *controller1 = [[tabBarController viewControllers] objectAtIndex:0];
[self configureTabBarItemWithImageName:#"home_ON.png" : #"home.png" andText:#"Trang chủ" forViewController:controller1];
UIViewController *controller2 = [[tabBarController viewControllers] objectAtIndex:1];
[self configureTabBarItemWithImageName:#"channel_ON.png" : #"tvChannel.png" andText:#"Kênh" forViewController:controller2];
}
and loginviewcontroller.m
- (IBAction)btnLogin:(id)sender {
[self performSegueWithIdentifier:#"idenLogin" sender:self];
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate loadInterface];
}
Secondly, when you touch on button "play", layout video shows and it works ok, but I want to auto rotate
note: This is interface on iphone and I fix Portrait in Summary, I'm still show landscape, How to do?
Can u download my code demo is here
in couple of words you need modal view for login screen.
Here is how I did it (from app delegate class). Note that I have my login view designed in storytboard.
- (void) showLoginView
{
assert(loginController == nil);
assert(activityView == nil);
UITabBarController *tabbar = (UITabBarController *)self.window.rootViewController;
loginController = [tabbar.storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
loginController.delegate = self;
[tabbar presentModalViewController:loginController animated:YES];
}
I create an object in my AppDelegate called WindowState or similar that manages what should be the rootViewController of the window. Initially it would be a sign in or splash, then you can run checks in your WindowState class and listen for notifications eg. MyAppDidSignInNotification then change the rootViewController of your app to a UITabBarController or whatever there.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.windowState = [[FASWindowState alloc] initWithWindow:self.window];
[self.window makeKeyAndVisible];
return YES;
}