不使用NSThread:performSelector:withObject:afterDelay:?

时间:2013-06-25 12:39:18

标签: objective-c selector nsthread

performSelector:withObject:afterDelay:是否可能无法在子线程中使用?

我还不熟悉客观c和Xcode,所以也许我错过了一些明显的东西......:/我真的很感激一些帮助。

我想要做的就是显示一个infolabel 3秒钟,之后它将被隐藏。如果设置了新信息,则3秒后隐藏标签的线程将被取消。 (我不希望通过旧线程隐藏新信息。)

源码:

- (void) setInfoLabel: (NSString*) labelText
{
   // ... update label with text ...

    infoLabel.hidden = NO;

    if(appDelegate.infoThread != nil) [appDelegate.infoThread cancel]; // cancel last hide-thread, if it exists

    NSThread *newThread = [[NSThread alloc] initWithTarget: self selector:@selector(setInfoLabelTimer) object: nil];// create new thread
    appDelegate.infoThread = newThread; // save reference
    [newThread start]; // start thread


    [self performSelector:@selector(testY) withObject: nil afterDelay:1.0];

}


-(void) setInfoLabelTimer
{
    NSLog(@"setInfoLabelTimer");


    [self performSelector:@selector(testX) withObject: nil afterDelay:1.0];

    [self performSelector:@selector(hideInfoLabel) withObject: nil afterDelay:3.0];

    NSLog(@"Done?");
}

-(void) testX
{
 NSLog(@"testX testX testX testX testX");

}

-(void) testY
{
    NSLog(@"testY testY testY testY testY");

}

-(void) hideInfoLabel
{
    NSLog(@"f hideInfoLabel");
    if(!([[NSThread currentThread] isCancelled])) {
        AppDelegate *appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
        appDelegate.infoThread = nil;
        appDelegate.infoLabel.hidden = YES;
        [NSThread exit];
    }
}

控制台 - 输出:

  • setInfoLabelTimer
  • 完成?
  • testY testY testY testY testY

正如您所见performSelector:withObject:afterDelay:正在工作(--->“testY testY testY testY testY testY”),但不在子线程中(运行(--->“setInfoLabelTimer”和“完成?”) “))

有谁知道为什么performSelector:withObject:afterDelay:在子线程中不起作用? (或者我的错是什么?:()

祝你好运, 茶壶

4 个答案:

答案 0 :(得分:1)

顺便说一下,您可能想考虑使用Grand Central Dispatch,GCD。如果你想在三秒内做一些事情,你可以:

double delayInSeconds = 3.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    // do stuff here, and because it's in the main queue, you can do UI stuff, too
});

我还会在并发编程指南中向您推荐Migrating Away From Threads


或者,您可以使用动画块,而不是使用GCD,您可以在3.0秒内指定想要发生的事情。您还可以设置该过渡的动画(在我的示例中为0.25秒),以便删除控件更加优雅:

[UIView animateWithDuration:0.25
                      delay:3.0
                    options:0
                 animations:^{
                     // you can, for example, visually hide in gracefully over a 0.25 second span of time

                     infoLabel.alpha = 0.0;
                 }
                 completion:^(BOOL finished) {
                     // if you wanted to actually remove the view when the animation was done, you could do that here

                     [infoLabel removeFromSuperview];
                 }];

答案 1 :(得分:1)

如果你正在运行一个'sub'线程(一个不是主线程的线程),它可以用以下两种方式之一运行:

  1. 它运行一个方法,然后终止
  2. 它运行一个运行循环并处理队列中的项目
  3. 如果线程以表单1运行,则使用performSelector会将项目放入队列(或至少尝试),但它永远不会被处理,线程将终止。

    如果您想在线程上使用performSelector,则需要执行其他工作。或者,您可以将项目推送到运行循环的主线程上。

答案 2 :(得分:1)

如果要在线程上调用performSelector:withObject:afterDelay,则此线程必须具有正在运行的RunLoop。查看Apple的Thread Programming Guide。这里也是RunLoop和NSThread的example

您可以在setInfoLabelTimer中添加以下代码:

while (!self.isCancelled)
{
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                            beforeDate:[NSDate distantFuture]];
}

答案 3 :(得分:0)

根本不需要线程或GCD来做你想做的事。

只需在主线程上直接使用performSelector:withObject:afterDelay:,就像@Rob指示的那样动画,在主队列上使用dispatch_afterNSTimer