我很确定这很简单,我只是遗漏了一些明显的东西。我有一个应用程序需要从Web服务下载数据以便在UITableView中显示,如果操作需要超过X秒才能完成,我想显示UIAlertView。所以这就是我所拥有的(简化为简洁):
MyViewController.h
@interface MyViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource> {
NSTimer *timer;
}
@property (nonatomic, retain) NSTimer *timer;
MyViewController.m
@implementation MyViewController
@synthesize timer;
- (void)viewDidLoad {
timer = [NSTimer scheduledTimerWithTimeInterval:20
target:self
selector:@selector(initializationTimedOut:)
userInfo:nil
repeats:NO];
[self doSomethingThatTakesALongTime];
[timer invalidate];
}
- (void)doSomethingThatTakesALongTime {
sleep(30); // for testing only
// web service calls etc. go here
}
- (void)initializationTimedOut:(NSTimer *)theTimer {
// show the alert view
}
我的问题是,我期待[self doSomethingThatTakesALongTime]
调用阻塞,而计时器一直在计数,我想如果它在计时器完成倒计时之前完成,它将返回线程的控制权到viewDidLoad
[timer invalidate]
将继续取消计时器。显然我对定时器/线程如何工作的理解是有缺陷的,因为编写代码的方式,定时器永远不会消失。但是,如果我删除[timer invalidate]
,则会删除。
答案 0 :(得分:3)
我认为在同一个线程上调度计时器和执行阻塞调用存在问题。在阻塞调用完成之前,运行循环无法触发计时器。
我建议你分离一个线程来执行长时间的操作。完成长操作后,回调主线程以使计时器无效。
注意:在计划的同一个线程上使计时器失效非常重要。
- (void)viewDidLoad {
timer = [NSTimer scheduledTimerWithTimeInterval:20
target:self
selector:@selector(initializationTimedOut:)
userInfo:nil
repeats:NO];
[NSThread detachNewThreadSelector:@selector(doSomethingThatTakesALongTime:) toTarget:self withObject:nil];
}
- (void)doSomethingThatTakesALongTime:(id)arg {
sleep(30); // for testing only
// web service calls etc. go here
[self performSelectorOnMainThread:@selector(invalidate) withObject:nil waitUntilDone:NO];
}
- (void)invalidate {
[timer invalidate];
}
- (void)initializationTimedOut:(NSTimer *)theTimer {
// show the alert view
}
答案 1 :(得分:0)
您是否尝试过使用[NSThread sleepforTimeInterval:30];
?
答案 2 :(得分:0)
sleep()
出现在主线程上,相关的运行循环永远不会有机会调用计时器的选择器。
如果您要在-doSomething
中进行实际工作但不阻止该主题,例如对Web服务的非阻塞调用,它将按预期工作。但是,阻塞调用必须在不同的线程中完成,因此主运行循环不会被阻塞。