1

I have a singleton class that checks the login status of the app.

There's a method named attemptToLogin in the singleton class that makes an http request with parameters and returns with json data about the login status. (true or false)

Now in the main TabBarViewController i did the following:

@interface CustomTabBarController ()

@end

@implementation CustomTabBarController{
    LoginCheckSingleton *loginSingleton;
    dispatch_queue_t myCustomQueue;
}
-(void)viewDidAppear:(BOOL)animated{
    myCustomQueue = dispatch_queue_create("com.myDomain.appName", NULL);
    loginSingleton = [LoginCheckSingleton sharedInstance];
    dispatch_sync(myCustomQueue, ^{
        [loginSingleton attemptToLogin];
    });
    if([loginSingleton.loginstat  isEqual: @"true"]){
        NSLog(@"Logged In");
    }else{
        NSLog(@"Not Logged In");
        [self performSegueWithIdentifier:@"goToLoginView" sender:self];
    }
}

The dispatch_sync is not working properly here, i want to execute the function inside the dispatch_sync and get the results before executing the if statement under it. But the if statement is executed before the block inside the dispatch_sync has finished.

This is the Singleton Class:

#import "LoginCheckSingleton.h"
#import "AFNetworking.h"
#import "SSKeychain.h"
#import "CustomTabBarController.h"
static LoginCheckSingleton *sharedInstance = nil;
@interface LoginCheckSingleton (){
    NSString *serverURLString;
    NSURL *serverURL;
    NSString *userId;
    NSString *password;
    NSString *email;
    NSMutableArray *jsonContents;
    NSMutableDictionary *dictionary;
    NSString *loggedInStatus;
    bool loggedInTF;

}

@end
@implementation LoginCheckSingleton{
}


+ (LoginCheckSingleton*) sharedInstance {
    static dispatch_once_t _singletonPredicate;
    static LoginCheckSingleton *_singleton = nil;

    dispatch_once(&_singletonPredicate, ^{
        _singleton = [[super allocWithZone:nil] init];
    });

    return _singleton;
}

+ (id) allocWithZone:(NSZone *)zone {
    return [self sharedInstance];
}

-(void)attemptToLogin{
    // Retrieve credentials from Keychain
    userId = [SSKeychain passwordForService:@"com.lazemni.iFresh"
                                      account:@"ifreshUserId"];
    password = [SSKeychain passwordForService:@"com.lazemni.iFresh"
                                      account:@"ifreshPassword"];
    email = [SSKeychain passwordForService:@"com.lazemni.iFresh"
                                   account:@"ifreshEmail"];
    if(email == nil || password == nil){

        NSLog(@"empty username or password");
    }else{
        NSLog(@"not empty username or password");
        serverURLString = @"http://www.lazemni.com/demo/ifresh/api/login/";
        serverURLString = [serverURLString stringByAppendingString:email];
        serverURLString = [serverURLString stringByAppendingString:@"/"];
        serverURLString = [serverURLString stringByAppendingString:password];
        NSLog(@"%@",serverURLString);
        serverURL = [NSURL URLWithString:serverURLString];

        NSURLRequest *request = [NSURLRequest requestWithURL:serverURL];
        //AFNetworking asynchronous url request
        AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
                                             initWithRequest:request];

        operation.responseSerializer = [AFJSONResponseSerializer serializer];
        [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
            jsonContents = [responseObject objectForKey:@"login"];
            NSLog(@"%@",jsonContents);
            dictionary = [jsonContents objectAtIndex:0];
            loggedInStatus = [dictionary objectForKey:@"status"];
            if([loggedInStatus  isEqual: @"true"]){
                NSLog(@"Succefully loggedin!");
                [SSKeychain setPassword:[dictionary objectForKey:@"user_id"] forService:@"com.lazemni.iFresh" account:@"ifreshUserId"];
                [SSKeychain setPassword:[dictionary objectForKey:@"email"] forService:@"com.lazemni.iFresh" account:@"ifreshEmail"];
                [SSKeychain setPassword:[dictionary objectForKey:@"password"] forService:@"com.lazemni.iFresh" account:@"ifreshPassword"];
                self.loginstat = @"true";
                loggedInTF = true;
            }else if([loggedInStatus  isEqual: @"false"]){
                NSLog(@"Wrong email/password combination!");
                self.loginstat = @"false";
                loggedInTF = false;
            }
        } failure:nil];
        [operation start];
    }
}


@end

I never understood how dispatch_sync really works, Any idea how to wait for the [loginSingleton attemptToLogin]; to finish ?

Fadi Obaji
  • 1,454
  • 4
  • 27
  • 57
  • What does attemptToLogin do? Why does it need to be in a dispatch closure at all? Why is not executed inline? – Mike Taverne Apr 05 '16 at 01:21
  • i added the singleton class with the called method, you can check it please – Fadi Obaji Apr 05 '16 at 01:24
  • You need to create a callback for `attemptToLogin` method, after checking login finish in that method, you execute that callback. And in `CustomTabBarController` move `if` statement to that callback block of `attemptToLogin` method – Gintama Apr 05 '16 at 02:19
  • @Gintama can you explain in code please :-) – Fadi Obaji Apr 05 '16 at 02:20
  • @FadiObaji because i cannot format code in comment so i add code as an answer, you can check it – Gintama Apr 05 '16 at 02:25

2 Answers2

2

attemptToLogin is probably an asynchronous method. You want to write attemptToLogin in such a way that it gives you a callback when the HTTP Request finishes executing. You can do that by means of a completion block, or a delegate, or a notification.

If you wait for the request to finish, you'll end up blocking the main thread, which will freeze user interactions, leading to a terrible UX.

rounak
  • 9,217
  • 3
  • 42
  • 59
1
- (void)attemptToLogin:(void(^)(BOOL login))complete {
   ...
   [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        ....
       // After you get login status
       complete(your_login_status_here);
   }
}

And in CustomTabBarController

-(void)viewDidAppear:(BOOL)animated{
    myCustomQueue = dispatch_queue_create("com.myDomain.appName", NULL);
    loginSingleton = [LoginCheckSingleton sharedInstance];

        [loginSingleton attemptToLogin:^(loginStatus){
               if([loginStatus  isEqual: @"true"]){
                   NSLog(@"Logged In");
               }else{
                    NSLog(@"Not Logged In");
                    dispatch_async(dispatch_get_main_queue(), {
                      [self performSegueWithIdentifier:@"goToLoginView" sender:self];
                    });
               }

        }];

}
Gintama
  • 1,152
  • 20
  • 35