【问题标题】:Not working with NSThread: performSelector:withObject:afterDelay:?不使用 NSThread: performSelector:withObject:afterDelay:?
【发布时间】:2013-06-25 23:46:20
【问题描述】:

performSelector:withObject:afterDelay: 有没有可能在子线程中不起作用?

我还是 Objective c 和 Xcode 的新手,所以我可能遗漏了一些明显的东西......:/我真的很感激一些帮助。

我想要做的就是显示一个信息标签 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”),但不能在子线程中工作(运行(--->“setInfoLabelTimer”和“Done?”))

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

最好的问候, 茶壶

【问题讨论】:

  • 是的,它不起作用。任何与视图相关的东西都必须放在 main 上。
  • .h 中定义的 testx 和 testy 方法?
  • 你不应该在后台线程中处理 UIKit 对象。

标签: objective-c selector nsthread


【解决方案1】:

如果你想在线程上调用 performSelector:withObject:afterDelay,这个线程必须有一个正在运行的 RunLoop。查看来自 Apple 的 Thread Programming Guide。这里还有一个 example 用于 RunLoop 和 NSThread。

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

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

【讨论】:

  • 谢谢 hrchen,你和 Rob 的帖子让我明白了这个问题!
  • 示例链接已损坏
【解决方案2】:

如果您正在运行“子”线程(不是主线程的线程),它可以通过以下两种方式之一运行:

  1. 它运行一个方法,然后终止
  2. 它运行一个运行循环并处理队列中的项目

如果线程以形式 1 运行,您使用 performSelector 会将项目放入队列(或至少尝试这样做)但它永远不会得到处理,线程将终止。

如果你想在线程上使用performSelector,你需要做额外的工作。或者,您可以将项目推送到正在运行运行循环的主线程。

【讨论】:

    【解决方案3】:

    顺便说一句,您可能需要考虑使用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];
                     }];
    

    【讨论】:

    • 非常感谢,罗伯!使用多线程确实不是最好的方法。:/
    【解决方案4】:

    完全不需要线程或 GCD 来做你想做的事情。

    只需在主线程上直接使用performSelector:withObject:afterDelay:,我们可以使用@Rob 指示的动画,在主队列上使用dispatch_after,或者NSTimer

    【讨论】:

    • 你好 bbum。没错,谢谢!它终于起作用了,我会在下次使用它之前阅读更多关于多线程的信息。花了我一整天...
    猜你喜欢
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 1970-01-01
    • 1970-01-01
    • 2012-07-22
    • 1970-01-01
    相关资源
    最近更新 更多