0

I'm trying to make a log in system for the app I am developing for a class project. This log in button would display on the navigation bar of most views so I was thinking of a separate class to initialize in the various view controllers to create the UIAlertView and handle the app to server communication. The issue I'm having is changing the Log In text to Log Out after the username and password has been checked and saved. I have been able to show the UIAlertView and talk with the server but am stuck on changing the text. I initially put a method in the view controller to change the text, with no success, but within the user file would be preferable. It is my first time using a singleton so I'm not interely sure on the correctness. Am I going about this the wrong way, is there a better way? Thanks for any help.

HomeViewController.m

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.navigationController setNavigationBarHidden:NO animated:YES];
    self.navigationController.navigationBar.topItem.title = @"Home";
    UIBarButtonItem *login = [[UIBarButtonItem alloc] initWithTitle:@"Log In" style:UIBarButtonItemStylePlain target:self action:@selector(log)];
    self.navigationController.navigationBar.topItem.rightBarButtonItem = login;
}
-(void)log {
    User* singleton = [User getInstance];
    [singleton sign];
}

/*
-(void)logfinish {
    if ([[NSUserDefaults standardUserDefaults] stringForKey:@"Username"] && [[NSUserDefaults standardUserDefaults] stringForKey:@"Password"]) {
        UIBarButtonItem *logout = [[UIBarButtonItem alloc] initWithTitle:@"Log Out" style:UIBarButtonItemStylePlain target:self action:nil];
        self.navigationController.navigationBar.topItem.rightBarButtonItem = logout;
    }
}*/

User.m

@implementation User

static User *singletonInstance;

+ (User*)getInstance{
    if (singletonInstance == nil) {
        singletonInstance = [[super alloc] init];
    }
    return singletonInstance;
}

-(void)sign {
    if (![[NSUserDefaults standardUserDefaults] stringForKey:@"Username"] && ![[NSUserDefaults standardUserDefaults] stringForKey:@"Password"]) {
        signAlert = [[UIAlertView alloc] initWithTitle:@"Log In" message:@"Please sign into your account" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Log In", nil];
        signAlert.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
        [signAlert show];
    }
}

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    NSString *person = [signAlert textFieldAtIndex:0].text;
    NSString *pass = [signAlert textFieldAtIndex:1].text;
    NSDictionary *params = @ {@"User": person, @"Password" :pass};

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    [manager GET:signIn parameters:params success:^(AFHTTPRequestOperation *operation, NSData* response) {
        NSString *responsef = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
        //NSLog(@"%@", responsef);
        [self check:responsef user:params];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Error: %@", error);
    }];
}

-(void)check:(NSString*) pass user:(NSDictionary*)nandp {
    if ([pass isEqualToString:@"Success"]) {
        [[NSUserDefaults standardUserDefaults] setValue:[nandp objectForKey:@"User"] forKey:@"Username"];
        [[NSUserDefaults standardUserDefaults] setValue:[nandp objectForKey:@"Password"] forKey:@"Password"];
        //NSLog(@"%@ logged in", [[NSUserDefaults standardUserDefaults] stringForKey:@"Username"]);
        //HomeViewController *view = [[HomeViewController alloc] init];
        //[view logfinish];
    }
    else NSLog(@"Failure");
}
  • Just something you should make note of. From the Apple documentation on UIAlertView, "*Important: UIAlertView is deprecated in iOS 8. (Note that UIAlertViewDelegate is also deprecated.) To create and manage alerts in iOS 8 and later, instead use UIAlertController with a preferredStyle of UIAlertControllerStyleAlert.*" – Jeffrey Mar 19 '15 at 02:56
  • what have you tried? U haven't written any code to change the title of the bar button item. Is that what you are asking for? – GoGreen Mar 19 '15 at 03:42
  • and regarding singletons, I suggest you use singleton API of GCD. Here is a good tutorial explaining the same: [iOS design patterns](http://www.raywenderlich.com/46988/ios-design-patterns) – GoGreen Mar 19 '15 at 03:43
  • I will be transitioning to UIAlertController once I have finished up other sections of the app. I have tried implementing a method within the view controller to check the NSUserDefault, create a new UIBarButtonItem and assigning it to the navigation bar; but I couldn't access the current navigation bar from the user class. Alloc/Init HomeViewController does not give the current ViewController. I have updated the code for what I have tried. – Blackhawk147 Mar 19 '15 at 03:58
  • try passing the viewController as a parameter to the singleton instance method `sign`. assign it to a separate instance variable declared in your singleton class. Then use this instance variable to call `logFinish`. That's one way of doing it. – GoGreen Mar 19 '15 at 04:05
  • Another way: pass the viewController as parameter in method `sign`. set it as the delegate for your alertView. You can then override the alertView clickedButtonAtIndex method in your respective class, i.e. `HomeViewController` in this case. – GoGreen Mar 19 '15 at 04:08
  • I will answer it with changes in your code whichever way you prefer, if you want it. Or you can try it yourself. – GoGreen Mar 19 '15 at 04:09
  • Thanks @GoGreen, I implemented it by passing the the view controller to the `sign` function, assigning it to a variable, and using it within `check` to change the button. If you would like, you can put your way of solving the question as an answer so that I can mark that it worked. – Blackhawk147 Mar 19 '15 at 13:11

1 Answers1

0

This is just one way of doing it. Declare an instance variable like:

@implementation User {
 UIViewController *viewController;
}

Pass the viewController you are calling from as a parameter to the method sign such as:

-(void)sign:(UIViewController *)viewControllerParam {
    if (![[NSUserDefaults standardUserDefaults] stringForKey:@"Username"] && ![[NSUserDefaults standardUserDefaults] stringForKey:@"Password"]) {
        signAlert = [[UIAlertView alloc] initWithTitle:@"Log In" message:@"Please sign into your account" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Log In", nil];
        signAlert.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
        viewController = viewControllerParam; // assigning to ivar for future use
        [signAlert show];
    }
}

Save this param to your instance variable for future reference.
Now you can use this variable for calling a method in your viewController which changes the right bar button item:

-(void)check:(NSString*) pass user:(NSDictionary*)nandp {
    if ([pass isEqualToString:@"Success"]) {
        [[NSUserDefaults standardUserDefaults] setValue:[nandp objectForKey:@"User"] forKey:@"Username"];
        [[NSUserDefaults standardUserDefaults] setValue:[nandp objectForKey:@"Password"] forKey:@"Password"];
        [viewController logfinish]; // call the respective method
    }
    else NSLog(@"Failure");
} 

Hope this helps! :)

GoGreen
  • 2,251
  • 1
  • 17
  • 29
  • this is just a dirty fix. You don't always have to replace the right bar button item. You can loop through the navigation items and then replace the title and selector instead. And as I pointed out earlier I strongly suggest you to use the GCD api for a singleton class: [dispatch_once](http://stackoverflow.com/a/9119089/2954866). Also check out this tutorial: [iOS design patterns](http://www.raywenderlich.com/46988/ios-design-patterns) – GoGreen Mar 19 '15 at 13:51