0

I have a method that needs calls another method which will have a callback made, I want my first method to wait until that callback is made to proceed. I am setting a flag on my callback, but I need the method to pick up the change.

I've tried a while loop but it takes up the main thread, dispatching it in the background also doesn't seem to work.

Seems like a simple task but I can't figure this out..

What I want is the while loop to exit after the variable is changed by my delegate method.

-(BOOL) keepAlive{
NSString *name = nil;
NSString *pw = nil;
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"login" accessGroup:nil];
name = [wrapper objectForKey:(__bridge id)kSecAttrAccount];
pw = [wrapper objectForKey:(__bridge id)kSecValueData];
//Call authentication
self.loginType = KeepAlive;
[self.loginManager authenticate:name andPass:pw];
self.loginStatus = loginPending;
while (1) {

    if(self.loginStatus == loginSuccess){
        return true;
    }else{
        return false;
    }

}
return false;

}

JDM
  • 883
  • 1
  • 8
  • 20
  • Just do whatever you need to do _in the callback_. That's the point of the callback -- so that you don't have to busy wait. – jscs Jun 25 '14 at 19:26

3 Answers3

2

Restructure your code.

Your Class containing keepAlive method should be a delegate implementing loginManagerProtocol.

Pass self to self.loginManagerProtocol setDelegate.

Then loginManager should create a protocol that defines a method didGetLoginStatus:.

In loginManager, once you get the callback, call [self.delegate didGetLoginStatus:status] to send it to your class holding keepAlive.

-(void)didGetLoginStatus:(bool)status{
   do something
}

You can find a more detailed explanation on how to implement a delegate here.

Community
  • 1
  • 1
LyricalPanda
  • 1,424
  • 14
  • 25
  • With the current protocol I could do this, The problem is I'm going to call this method if my session is "dead".. And I don't want other classes making calls to the web service without ensuring a valid session. I wouldn't want every class to have to implement the delegate methods.. – JDM Jun 25 '14 at 19:27
  • 2
    Gotcha. That sounds like a UI/UX problem - take a look at `MBProgressHud` on github for a nice control that will lock the screen with a loading sign. This is done when loading and you don't want the user to move around the app until it's done. So once you get a return, dismiss the progressHud and either push them into the app or pop them back to the login screen – LyricalPanda Jun 25 '14 at 19:30
1

Another alternative to using delegates is callback blocks:

You can define your login method similar to this:

 - (void)loginWithCallbackBlock:((^)(BOOL))callback;

You can add the callback() to the part where you get the response and the block will only be executed after receiving response.

You can call you method someway like this:

 [loginManager loginWithCallbackBlock:^(BOOL success) {
      //Go to next screen.
 }];
Lord Zsolt
  • 6,492
  • 9
  • 46
  • 76
0

Firstly I agree with LyricalPanda that you need to restructure your code.

If you believe the code you wrote suits best to your project, alternative is to use runloops. Sample code.

CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent();
    CFArrayRef allCurrentRunLoopModes = CFRunLoopCopyAllModes(currentRunLoop);
    while (self.loginStatus == loginPending)
    {
        for(NSString *runLoopMode in (__bridge NSArray *)allCurrentRunLoopModes)
        {
            CFRunLoopRunInMode((__bridge CFStringRef)runLoopMode,0.01(change it to suit your need)>,false);
        }
    }
    CFRelease(allCurrentRunLoopModes);

   if(self.loginStatus == loginSuccess){
        return true;
    }else{
        return false;
    }
uday
  • 1
  • 1
  • Thanks, this seems to work perfectly. While I'm not 100% sold on this code, it seems to be a good way for what I'm doing. I'll discuss with some of the other more experienced devs and see how they feel.... – JDM Jun 25 '14 at 19:39
  • No , if we run the runloop with appropriate run loop mode, UI won't be blocked. We used to do this in our project some time back. But we restructured our code and moved to blocks. – uday Jun 25 '14 at 19:50
  • It looks like in some cases, the rest of the app is getting blocked so I never get to see the value change.. I'm using the code as posted above and have tried a couple of different things, is it possible for the run loop to let my app continue in between runs? – JDM Jun 26 '14 at 16:25