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 ....

user1028028
  • 6,323
  • 9
  • 34
  • 59
  • 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). – Wain Aug 15 '13 at 09:31
  • That's how I'm creating the thread ... [self.botThread start]; ... That calls the NSThread subclass PSBotThread main method .. . – user1028028 Aug 15 '13 at 09:36
  • But what does it do? Where is the `sleepForTimeInterval` at? – Wain Aug 15 '13 at 09:38
  • the thread uses an object that will receive the messages and return a result... the sleepForTimeInterval is inside this object – user1028028 Aug 15 '13 at 11:16

3 Answers3

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
    }); 
});
Jason Fox
  • 5,115
  • 1
  • 15
  • 34
John
  • 2,672
  • 2
  • 23
  • 29
  • I don't think this will work ... maybe the thread creatoin should be in the dispatch_async ? – user1028028 Aug 15 '13 at 11:17
  • 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. – John Aug 15 '13 at 16:30
  • To me it blocks main thread...If you can, help me with this question http://stackoverflow.com/questions/32910632/objective-c-freezed-gui-also-with-queue?noredirect=1#comment53652781_32910632 – volperossa Oct 03 '15 at 13:19
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];
sbarow
  • 2,759
  • 1
  • 22
  • 37
  • I don't need to make it sleep from the main thread... it should make itself sleep after receiving a message from the main thread – user1028028 Aug 15 '13 at 11:47
  • Okay so you want it to sleep in the method - (void)messageForBot:(NSData *)msg ? – sbarow Aug 15 '13 at 11:48
  • 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 now – user1028028 Aug 15 '13 at 11:56
  • 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]; – sbarow Aug 15 '13 at 12:00
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
    })
}
Brian
  • 30,156
  • 15
  • 86
  • 87