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];
}
}
控制台 - 输出:
正如您所见performSelector:withObject:afterDelay:
正在工作(--->“testY testY testY testY testY testY”),但不在子线程中(运行(--->“setInfoLabelTimer”和“完成?”) “))
有谁知道为什么performSelector:withObject:afterDelay
:在子线程中不起作用? (或者我的错是什么?:()
祝你好运, 茶壶
答案 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运行,则使用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_after
或NSTimer
。