NSThread睡眠一段时间会阻塞主线程

15

我希望模拟与服务器的通信。由于远程服务器会有一些延迟,因此我想使用一个后台线程

 [NSThread sleepForTimeInterval:timeoutTillAnswer];

使用NSThread子类创建线程并启动...但是我注意到sleepForTimeInterval会阻塞主线程...为什么???NSThread默认不是后台线程吗?

线程是这样创建的:

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

更多信息: 这是机器人线程子类。

- (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];
}

我希望从主线程调用“messageForBot”... 同时后台线程应该调用主线程上的一个方法进行通信... 时间间隔的睡眠在gManager对象内部....


展示你是如何创建线程的,它的功能是什么以及何时调用 sleepForTimeInterval:(它会在被调用时延迟当前线程)。 - Wain
这就是我创建线程的方式... [self.botThread start]; ... 这会调用NSThread子类PSBotThread的主方法... - user1028028
但它是做什么的?sleepForTimeInterval在哪里? - Wain
线程使用一个接收消息并返回结果的对象... sleepForTimeInterval 函数在这个对象内部。 - user1028028
3个回答

23

它会阻塞当前运行sleepForTimeInterval方法的线程。将其在另一个线程上运行,以模拟服务器延迟,如下所示:

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
    }); 
});

我认为这不会起作用...也许线程创建应该在dispatch_async中进行? - user1028028
我正在使用它,而且它运行得很好。我做了同样的事情来模拟网络延迟。dispatch_queue_create已经创建了另一个线程。在dispatch_async中的sleepForTimeInterval将导致该线程休眠。 - John
对我来说,它阻塞了主线程...如果可以的话,请帮我解决这个问题:http://stackoverflow.com/questions/32910632/objective-c-freezed-gui-also-with-queue?noredirect=1#comment53652781_32910632 - volperossa

1
尝试在您的线程类中创建一个名为sleepThread的方法。
-(void)sleepThread
{
   [NSThread sleepForTimeInterval:timeoutTillAnswer];
}

然后在您的主线程中让它休眠。
[self.botThread performSelector:@selector(sleepThread) onThread:self.botThread withObject:nil waitUntilDone:NO];

从您的机器人线程向主线程发送更新。
dispatch_async(dispatch_get_main_queue(), ^{
    [MainClass somethinghasUpdated];
});

小提示

我认为创建RunLoop所需的全部只是:

// Run the Current RunLoop
[[NSRunLoop currentRunLoop] run];

我不需要从主线程使它休眠... 它应该在接收到主线程的消息后自己休眠。 - user1028028
好的,所以你想让它在方法 - (void)messageForBot:(NSData *)msg 中休眠? - sbarow
不,那个方法会调用主方法中创建的内部对象之一...我需要它睡眠...而不像现在一样阻塞用户界面。 - user1028028
好的,所以你的主线程将调用messageForBot:方法,该方法将调用comManager,然后再调用sleep。要从主线程调用messageBot,请执行以下操作 [self.botThread performSelector:@selector(messageForBot :) onThread:self.botThread withObject:someDataObject waitUntilDone:NO]; - sbarow

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
    })
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接