Objective-C:阻塞线程直到 NSTimer 完成(iOS)

发布于 2024-11-03 10:01:28 字数 2385 浏览 2 评论 0原文

我一直在寻找并尝试为自己编程来回答这个问题。

我的 mainView 控制器内有一个辅助线程正在运行,该线程正在运行一个倒数到 0 的计时器。

当该计时器正在运行时,启动该计时器的辅助线程应该被暂停/阻止。

当计时器达到 0 时,辅助线程应该继续。

我已经尝试过 NSCondition 和 NSConditionLock 但没有效果,所以理想情况下我喜欢用代码解决我的问题的解决方案,或者为我指出如何解决这个问题的指南。不是简单地声明“使用 X”的。

- (void)bettingInit {    
    bettingThread = [[NSThread alloc] initWithTarget:self selector:@selector(betting) object:nil];
    [bettingThread start];
}

- (void)betting {

    NSLog(@"betting Started");
    for (int x = 0; x < [dealerNormalise count]; x++){
        NSNumber *currSeat = [dealerNormalise objectAtIndex:x];
        int currSeatint = [currSeat intValue];
        NSString *currPlayerAction = [self getSeatInfo:currSeatint objectName:@"PlayerAction"];
        if (currPlayerAction != @"FOLD"){
            if (currPlayerAction == @"NULL"){                
                [inactivitySeconds removeAllObjects];
                NSNumber *inactivitySecondsNumber = [NSNumber numberWithInt:10];
                runLoop = [NSRunLoop currentRunLoop];
                betLooper = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(betLoop) userInfo:nil repeats:YES];
                [runLoop addTimer:[betLooper retain] forMode:NSDefaultRunLoopMode];
                [runLoop run];

                // This Thread needs to pause here, and wait for some input from the other thread, then continue on through the for loop

                NSLog(@"Test");
            }
        }
    }
}

- (void)threadKiller {
    [betLooper invalidate];

    //The input telling the thread to continue can alternatively come from here
    return;
}

- (void)betLoop {
    NSLog(@"BetLoop Started");
    NSNumber *currentSeconds = [inactivitySeconds objectAtIndex:0];
    int currentSecondsint = [currentSeconds intValue];
    int newSecondsint = currentSecondsint - 1;
    NSNumber *newSeconds = [NSNumber numberWithInt:newSecondsint];
    [inactivitySeconds replaceObjectAtIndex:0 withObject:newSeconds];
    inacTimer.text = [NSString stringWithFormat:@"Time: %d",newSecondsint];                      

    if (newSecondsint == 0){

        [self performSelector:@selector(threadKiller) onThread:bettingThread  withObject:nil waitUntilDone:NO];

        // The input going to the thread to continue should ideally come from here, or within the threadKiller void above
    }
}

I've been searching for and attempting to program for myself, an answer to this question.

I've got a secondary thread running inside my mainView controller which is then running a timer which counts down to 0.

Whilst this timer is running the secondary thread which initiated the timer should be paused/blocked whatever.

When the timer reaches 0 the secondary thread should continue.

I've Experimented with both NSCondition and NSConditionLock with no avail, so id ideally like solutions that solve my problem with code, or point me to a guide on how to solve this. Not ones that simply state "Use X".

- (void)bettingInit {    
    bettingThread = [[NSThread alloc] initWithTarget:self selector:@selector(betting) object:nil];
    [bettingThread start];
}

- (void)betting {

    NSLog(@"betting Started");
    for (int x = 0; x < [dealerNormalise count]; x++){
        NSNumber *currSeat = [dealerNormalise objectAtIndex:x];
        int currSeatint = [currSeat intValue];
        NSString *currPlayerAction = [self getSeatInfo:currSeatint objectName:@"PlayerAction"];
        if (currPlayerAction != @"FOLD"){
            if (currPlayerAction == @"NULL"){                
                [inactivitySeconds removeAllObjects];
                NSNumber *inactivitySecondsNumber = [NSNumber numberWithInt:10];
                runLoop = [NSRunLoop currentRunLoop];
                betLooper = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(betLoop) userInfo:nil repeats:YES];
                [runLoop addTimer:[betLooper retain] forMode:NSDefaultRunLoopMode];
                [runLoop run];

                // This Thread needs to pause here, and wait for some input from the other thread, then continue on through the for loop

                NSLog(@"Test");
            }
        }
    }
}

- (void)threadKiller {
    [betLooper invalidate];

    //The input telling the thread to continue can alternatively come from here
    return;
}

- (void)betLoop {
    NSLog(@"BetLoop Started");
    NSNumber *currentSeconds = [inactivitySeconds objectAtIndex:0];
    int currentSecondsint = [currentSeconds intValue];
    int newSecondsint = currentSecondsint - 1;
    NSNumber *newSeconds = [NSNumber numberWithInt:newSecondsint];
    [inactivitySeconds replaceObjectAtIndex:0 withObject:newSeconds];
    inacTimer.text = [NSString stringWithFormat:@"Time: %d",newSecondsint];                      

    if (newSecondsint == 0){

        [self performSelector:@selector(threadKiller) onThread:bettingThread  withObject:nil waitUntilDone:NO];

        // The input going to the thread to continue should ideally come from here, or within the threadKiller void above
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

云雾 2024-11-10 10:01:28

您不能在线程上运行计时器并同时使线程休眠。您可能需要重新考虑是否需要线程。

这里有一些事情需要指出。首先,当您安排计时器时:

betLooper = [NSTimer scheduledTimerWithTimeInterval:1 
                                             target:self 
                                           selector:@selector(betLoop:) 
                                           userInfo:nil 
                                            repeats:YES];

它会添加到当前运行循环并由当前运行循环保留 通过该方法,因此您无需手动执行此操作。只需[myRunLoop run]。你的计时器的选择器参数也是无效的——计时器的“目标方法”需要看起来像这样

- (void)timerFireMethod:(NSTimer *)tim;

这也意味着如果您只想使计时器无效,则不需要保留计时器,因为您将从该方法内部获得对它的引用。

其次,不清楚“该线程需要睡眠以等待输入”是什么意思。当您安排该计时器时,将在同一线程上调用方法 (betLoop)。如果您要使线程休眠,计时器也会停止。

您似乎对方法/线程有点困惑。 方法 bet 正在您的线程上运行。它本身不是一个线程,并且可以从该线程上的 bet 调用其他方法。如果您希望一个方法等待另一个方法完成,您只需在第一个方法中调用第二个方法即可:

- (void)doSomethingThenWaitForAnotherMethodBeforeDoingOtherStuff {
    // Do stuff...
    [self methodWhichINeedToWaitFor];
    // Continue...
}

我想您只是想让 betting 返回;运行循环将使线程保持运行,正如我所说,您从线程上的方法调用的其他方法也在线程上。然后,当你完成倒计时后,调用另一个方法来完成任何需要完成的工作(你也可以使 betLoop: 中的计时器无效),并完成线程:

- (void)takeCareOfBusiness {
  // Do the things you were going to do in `betting`
  // Make sure the run loop stops; invalidating the timer doesn't guarantee this
  CFRunLoopStop(CFRunLoopGetCurrent());    
  return;    // Thread ends now because it's not doing anything.
}

最后,由于计时器的方法在同一个线程上,不需要使用performSelector:onThread:...;正常调用该方法即可。

您应该查看 线程编程指南

另外,不要忘记释放您创建的 bettingThread 对象。

You can't run a timer on a thread and sleep the thread at the same time. You may want to reconsider whether you need a thread at all.

There's a few things that need to be pointed out here. First, when you schedule your timer:

betLooper = [NSTimer scheduledTimerWithTimeInterval:1 
                                             target:self 
                                           selector:@selector(betLoop:) 
                                           userInfo:nil 
                                            repeats:YES];

it's added to and retained by the current run loop by that method, so you don't need to do that manually. Just [myRunLoop run]. Your timer's selector argument is also invalid -- a timer's "target method" needs to look like this:

- (void)timerFireMethod:(NSTimer *)tim;

This also means that you don't need to retain the timer if all you want to do is invalidate it, since you will have a reference to it from inside that method.

Second, it's not clear what you mean by "this thread needs to sleep to wait for input". When you schedule that timer, the method (betLoop) is called on the same thread. If you were to sleep the thread, the timer would stop too.

You seem to be a little mixed up regarding methods/threads. The method betting is running on your thread. It is not itself a thread, and it's possible to call other methods from betting that will also be on that thread. If you want a method to wait until another method has completed, you simply call the second method inside the first:

- (void)doSomethingThenWaitForAnotherMethodBeforeDoingOtherStuff {
    // Do stuff...
    [self methodWhichINeedToWaitFor];
    // Continue...
}

I think you just want to let betting return; the run loop will keep the thread running, and as I said, the other methods you call from methods on the thread are also on the thread. Then, when you've done the countdown, call another method to do whatever work needs to be done (you can also invalidate the timer inside betLoop:), and finalize the thread:

- (void)takeCareOfBusiness {
  // Do the things you were going to do in `betting`
  // Make sure the run loop stops; invalidating the timer doesn't guarantee this
  CFRunLoopStop(CFRunLoopGetCurrent());    
  return;    // Thread ends now because it's not doing anything.
}

Finally, since the timer's method is on the same thread, you don't need to use performSelector:onThread:...; just call the method normally.

You should take a look at the Threading Programming Guide.

Also, don't forget to release the bettingThread object that you created.

尬尬 2024-11-10 10:01:28

NSThread 有一个类方法+ (void)sleepForTimeInterval:(NSTimeInterval)ti。看看这个:)。

NSThread has a class method + (void)sleepForTimeInterval:(NSTimeInterval)ti. Have a look at this :).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文