首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不使用NSThread: performSelector:withObject:afterDelay:?

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

Stack Overflow用户
提问于 2013-06-25 12:39:18
回答 4查看 1.9K关注 0票数 0

是否有可能performSelector:withObject:afterDelay:在子线程中不工作?

我对目标C和Xcode还不熟悉,所以我可能遗漏了一些显而易见的东西./我真的很想得到一些帮助。

我所要做的就是用3秒的时间展示一个字母,然后它就会被隐藏起来。如果设置了新信息,3秒后隐藏标签的线程将被取消。(我不希望旧线程隐藏新信息。)

Sourcecode:

代码语言:javascript
复制
- (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];
    }
}

Console-Output:

  • setInfoLabelTimer
  • 完成了吗?
  • testY testY

如您所见,performSelector:withObject:afterDelay:确实工作(-->“testY testY"),但在子线程(运行(-->”setInfoLabelTimer“和”Done?“))中不起作用。

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

向你问好,茶壶

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-06-25 14:04:33

如果要在线程上调用执行器:withObject:afterDelay,则该线程必须具有一个正在运行的RunLoop。看看苹果的线程编程指南。这里还有一个示例,用于RunLoop和NSThread。

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

代码语言:javascript
复制
while (!self.isCancelled)
{
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                            beforeDate:[NSDate distantFuture]];
}
票数 1
EN

Stack Overflow用户

发布于 2013-06-25 13:29:40

顺便提一下,您可能想考虑使用中央调度、GCD。如果你想在三秒钟内完成某件事,你可以:

代码语言:javascript
复制
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
});

我还将在并发编程指南中向您推荐从线程迁移

或者,与使用GCD不同,您可以使用一个动画块,在该块中,您可以指定您希望在3.0秒内发生的事情。您还可以激活该转换(在我的示例中是0.25秒),这样删除控件就更优雅了:

代码语言:javascript
复制
[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
EN

Stack Overflow用户

发布于 2013-06-25 13:30:40

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

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

如果线程以表单1运行,那么使用performSelector将一个项放入队列(或至少尝试),但它永远不会被处理,线程就会终止。

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17297595

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档