NSThread sleepfortimeinterval blocks main thread
Asked Answered
J

3

15

I want to simulate a communication with a server. As the remote server will have some delays I want to use a background thread that has on it

 [NSThread sleepForTimeInterval:timeoutTillAnswer];

The thread is created with NSThread sub classing and started ... However I noticed that sleepForTimeInterval is blocking the main thread... Why??? Isn't a NSThread a backgroundThread by default?

This is how the thread is created:

   self.botThread = [[PSBotThread alloc] init];
    [self.botThread start];

Further info: This is the bot thread subclas

- (void)main
{
    @autoreleasepool {
        self.gManager = [[PSGameManager alloc] init];
        self.comManager = [[PSComManager alloc] init];
        self.bot = [[PSBotPlayer alloc] initWithName:@"Botus" andXP:[NSNumber numberWithInteger:1500]];
        self.gManager.localPlayer = self.bot;
        self.gManager.comDelegate = self.comManager;
        self.gManager.tillTheEndGame = NO;
        self.gManager.localDelegate = self.bot;
        self.comManager.gameManDelegate = self.gManager;
        self.comManager.isBackgroundThread = YES;
        self.comManager.logginEnabled = NO;
        self.gManager.logginEnabled = NO;
        self.bot.gameDelegate = self.gManager;
        BOOL isAlive = YES;
        // set up a run loop
        NSRunLoop *runloop = [NSRunLoop currentRunLoop];
        [runloop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [self.gManager beginGameSP];
        while (isAlive) { // 'isAlive' is a variable that is used to control the thread existence...
            [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }



    }
}

- (void)messageForBot:(NSData *)msg
{
    [self.comManager didReceiveMessage:msg];
}

I want to call "messageForBot" from the main thread... also the background thread should call a method on the main thread to communicate.. The sleep for time intervail in inside the gManager object ....

Justinajustine answered 15/8, 2013 at 9:21 Comment(4)
Show how you're creating the thread, what it does and when you call sleepForTimeInterval: (which delays the current thread at the time it's called).Jaddan
That's how I'm creating the thread ... [self.botThread start]; ... That calls the NSThread subclass PSBotThread main method .. .Justinajustine
But what does it do? Where is the sleepForTimeInterval at?Jaddan
the thread uses an object that will receive the messages and return a result... the sleepForTimeInterval is inside this objectJustinajustine
N
23

It blocks whatever thread sleepForTimeInterval is running on. Run it on another thread to simulate your server delay like this:

dispatch_queue_t serverDelaySimulationThread = dispatch_queue_create("com.xxx.serverDelay", nil);
dispatch_async(serverDelaySimulationThread, ^{
     [NSThread sleepForTimeInterval:10.0];
     dispatch_async(dispatch_get_main_queue(), ^{
            //Your server communication code here
    }); 
});
Nevlin answered 15/8, 2013 at 9:42 Comment(3)
I don't think this will work ... maybe the thread creatoin should be in the dispatch_async ?Justinajustine
I am using it and it works fine. I did the same thing to simulate network latency. The dispatch_queue_create already created another thread. The sleepForTimeInterval in dispatch_async will cause that thread to sleep.Nevlin
To me it blocks main thread...If you can, help me with this question #32911132Antipasto
S
1

Try create a method in your thread class called sleepThread

-(void)sleepThread
{
   [NSThread sleepForTimeInterval:timeoutTillAnswer];
}

Then to make it sleep from your main thread

[self.botThread performSelector:@selector(sleepThread) onThread:self.botThread withObject:nil waitUntilDone:NO];

To send updated to your main thread from your bot thread.

dispatch_async(dispatch_get_main_queue(), ^{
    [MainClass somethinghasUpdated];
});

Side Note

To create the RunLoop I think all you need to do is

// Run the Current RunLoop
[[NSRunLoop currentRunLoop] run];
Stettin answered 15/8, 2013 at 11:41 Comment(4)
I don't need to make it sleep from the main thread... it should make itself sleep after receiving a message from the main threadJustinajustine
Okay so you want it to sleep in the method - (void)messageForBot:(NSData *)msg ?Stettin
NO, that method will call another on one of the internal objects created in the main method ... there I need it to sleep ... without blocking the UI like it does nowJustinajustine
Okay so your main thread will call messageForBot: that method will then call your comManager and that will then invoke the sleep. To call messageBot from the main thread do this [self.botThread performSelector:@selector(messageForBot:) onThread:self.botThread withObject:someDataObject waitUntilDone:NO];Stettin
O
0

Swift:

let nonBlockingQueue: dispatch_queue_t = dispatch_queue_create("nonBlockingQueue", DISPATCH_QUEUE_CONCURRENT)
dispatch_async(nonBlockingQueue) {
    NSThread.sleepForTimeInterval(1.0)
    dispatch_async(dispatch_get_main_queue(), {
        // do your stuff here
    })
}
Outlive answered 5/5, 2016 at 14:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.