Search code examples
iosnsthreadnscondition

Pause Main thread until background thread retrieves user input


In my main starting thread I need to pause the code and start a new thread and wait until I get user input. Then Id like to discard the new thread made and go back to where the main thread left off. But whats happening is that the new thread is called but the main thread keeps going with the code. How do I deal with this without interfering with the user being able to use the interface buttons? I think that maybe another nscondition needs to be made in my if(moveCount == 2) statement? Or that my main thread needs to wait for a signal from my other thread notifying user input is received.

ADDITIONAL NOTE: I would also like the original thread paused in such a way that I can still use my 2 UIButtons in my interface.

MORE ADDITIONAL NOTES AS TO THE QUESTIONS IM RECEIVING: This is a game I'm making. Somewhere mid code means in my main thread in one of my methods. This method decides which direction I'm moving in then i get a tag difference, then make an attack. But sometimes 2 attacks can be made so its at this point the user has 2 buttons to click on the screen to decide which attack to make.

Also its quiet clear to me that I should not pause the main thread now. If so what is the alternative? Thanks

NSCondition and NSThread

@property (strong, nonatomic) NSCondition *condition;
@property (strong, nonatomic) NSThread *aThread;

In my viewDidLoad create the following.

// create the NSCondition instance
self.condition = [[NSCondition alloc]init];

// create the thread
self.aThread = [[NSThread alloc] initWithTarget:self selector:@selector(threadLoop) object:nil];

somewhere mid code..

if(moveCount == 2){

        [self.aThread start];
    }

   // I need to get captureDecision from user from 2 buttons before continue.. How do I pause this thread when aThread is started. Then when capture decision is received discard aThread and start here.

    NSLog(@"Capture Decision = %d", captureDecision);
    if(captureDecision == 1){

        tagDifference = newButton.tag - currentButton.tag;

    }else{

        tagDifference = currentButton.tag - newButton.tag;

    }
}

aThread Method

-(void)threadLoop{

    NSLog(@"Thread Loop Triggered");
    while([[NSThread currentThread] isCancelled] == NO)
    {
        [self.condition lock];
        while(captureDecision == 0)
        {
            [self.condition wait];
        }

        [self.condition unlock];
    }
    [NSThread exit]; //exit this thread when user input is received
}

Solution

  • What you are requesting is not possible, the main thread IS the one that handles user interactions, whenever you "halt" the main thread the interface becomes unresponsive.

    Based on apple's documentation:

    The main run loop of your app is responsible for processing all user-related events. The UIApplication object sets up the main run loop at launch time and uses it to process events and handle updates to view-based interfaces. As the name suggests, the main run loop executes on the app’s main thread. This behavior ensures that user-related events are processed serially in the order in which they were received.

    Which means that if you halt the main thread you won't be able to. https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW14

    (Unless there is some strange way to make a background thread handle the user interactions which i might not be aware of, but still its pretty strange)

    As others have told you here, your approach is far from optimal. Questions you have to ask yourself are, in what part of the code do you want to wait for a certain event to occur, and for what purpose.

    If you give us a more detailed explanation of what you want to achieve then we can offer you a much better solution.

    EDIT:

    What kind of game is it? turn based? something that gets drawn constantly like with a timer. Basically you have to use functions, for example, if it was a card game, you would lay all the cards and wait for user input, when the user hits the button you would run "calculate outcome function" and make the proper changes in the board and wait for the next input.

    If you want to pause the thread i would assume it is because something is running constantly, there is a special timer that syncs with the screen called CADisplayLink

    https://developer.apple.com/LIBRARY/IOS/documentation/QuartzCore/Reference/CADisplayLink_ClassRef/Reference/Reference.html

    You can even "pause" this timer to wait for an input from the user.

    BTW, if you DONT want to let the user interact with the interface until an event occurs all you have to do is, self.view.userInteractionEnabled = NO; this disables all interactions on the screen until you set it back to "YES".

    EDIT 2:

    The way you change the flow varies on what you are using to make your game, OpenGL? Quartz2D? simple views?

    It kinda feels you are a bit lost, you might wanna start from here:

    http://www.raywenderlich.com/tutorials (Scroll down to the making games part)