题 NSThread sleepfortimeinterval阻止主线程


我想模拟与服务器的通信。由于远程服务器会有一些延迟,我想使用它上面的后台线程

 [NSThread sleepForTimeInterval:timeoutTillAnswer];

该线程是使用NSThread子类创建并启动的...但是我注意到sleepForTimeInterval阻塞了主线程...为什么???默认情况下,NSThread不是backgroundThread吗?

这是线程的创建方式:

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

更多信息: 这是bot线程子类

- (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对象内部进行干扰....


15
2017-08-15 09:21


起源


显示您如何创建线程,它的作用以及何时调用 sleepForTimeInterval: (在调用时延迟当前线程)。 - Wain
这就是我创建线程的方式...... [self.botThread start]; ...调用NSThread子类PSBotThread主方法.. - user1028028
但是它做了什么?哪儿是 sleepForTimeInterval 在? - Wain
该线程使用一个将接收消息并返回结果的对象... sleepForTimeInterval在此对象内 - user1028028


答案:


它阻止运行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
    }); 
});

22
2017-08-15 09:42



我认为这不会起作用...也许线程创建应该在dispatch_async中? - user1028028
我正在使用它,它工作正常。我做了同样的事情来模拟网络延迟。 dispatch_queue_create已经创建了另一个线程。 dispatch_async中的sleepForTimeInterval将导致该线程进入休眠状态。 - John
它对我也有用:-) - Donald
对我来说它阻止了主线......如果可以的话,请帮我解决这个问题 stackoverflow.com/questions/32910632/... - volperossa
按预期工作....使用单元测试。 - Jedidja


尝试在名为sleepThread的线程类中创建一个方法

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

然后让它从你的主线程中休眠

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

从bot线程发送更新到主线程。

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

边注

要创建RunLoop,我认为您需要做的就是

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

1
2017-08-15 11:41



我不需要让它从主线程中休眠......它应该在从主线程收到消息后让自己睡觉 - user1028028
好的,所以你希望它在方法中睡觉 - (void)messageForBot:(NSData *)msg? - sbarow
不,那个方法会在main方法中创建的一个内部对象上调用另一个...我需要它才能睡觉...而不像现在那样阻止UI - user1028028
好的,所以你的主线程将调用messageForBot:然后该方法将调用你的comManager,然后调用sleep。要从主线程调用messageBot,请执行此操作[self.botThread performSelector:@selector(messageForBot :) onThread:self.botThread withObject:someDataObject waitUntilDone:NO]; - sbarow
不起作用.... - user1028028


迅速:

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

0
2018-05-05 14:17