2013-06-25 44 views
0

是否有可能performSelector:withObject:afterDelay:在子线程中不起作用?不适用于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
  • 完成?
  • 暴躁易怒暴躁易怒暴躁

正如你可以看到performSelector:withObject:afterDelay:不工作(--->“暴躁易怒暴躁易怒暴躁的”),但不是在子线程(它运行(--->“setInfoLabelTimer “和”完成?“))

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

最好的问候, 茶壶

+0

是的,它不工作。任何视图相关的东西都必须是主要的。 –

+0

testx和testy方法在.h中定义? –

+0

你不应该搞乱后台线程中的UIKit对象。 – bbum

回答

1

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

可以在setInfoLabelTimer添加以下代码:

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

谢谢hrchen,你和Robs的帖子让我明白这个问题! – Teapot

+0

示例链接中断 – ademar111190

0

顺便说一句,你可能要考虑与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

非常感谢,Rob!使用多线程真的不是最好的方法。:/ – Teapot

1

如果你正在运行一个“子”线程(ISN线程“T主线程),它可以在2的一个方式运行:

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

如果线程运行在表单1中,您使用performSelector将项目放入队列中(或至少尝试)但它永远不会被处理,线程将会终止。

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

+0

谢谢,Wain! :) – Teapot

0

无需线程或GCD都做你想做的事情。

只需直接在主线程使用performSelector:withObject:afterDelay:,我们的动画作为@Rob指出,在主队列,或NSTimer使用dispatch_after

+0

Hello bbum。没错,谢谢!它终于有效,我会在下次使用它之前阅读更多有关多个线程的内容。带了我一整天... – Teapot

相关问题