NSTimer作为超时机制
我很确定这真的很简单,我只是错过了一些明显的东西。我有一个应用程序需要从 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]
,它就会发生。
I'm pretty sure this is really simple, and I'm just missing something obvious. I have an app that needs to download data from a web service for display in a UITableView, and I want to display a UIAlertView if the operation takes more than X seconds to complete. So this is what I've got (simplified for brevity):
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
}
My problem is that I'm expecting the [self doSomethingThatTakesALongTime]
call to block while the timer keeps counting, and I'm thinking that if it finishes before the timer is done counting down, it will return control of the thread to viewDidLoad
where [timer invalidate]
will proceed to cancel the timer. Obviously my understanding of how timers/threads work is flawed here because the way the code is written, the timer never goes off. However, if I remove the [timer invalidate]
, it does.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为调度计时器并在同一线程上执行阻塞调用存在问题。在阻塞调用完成之前,运行循环无法触发计时器。
我建议您分离一个线程来执行长操作。一旦长操作完成,回调主线程以使计时器失效。
注意:使计划的同一线程上的计时器无效非常重要。
I think there is a problem with scheduling a timer and doing a blocking call on the same thread. Until the blocking call is completed, the run-loop cannot fire the timer.
I suggest you to detach a thread to perform the long operation. Once the long operation is finished, call back on the main thread to invalidate the timer.
Note: it is important to invalidate the timer on the same thread it was scheduled.
您是否尝试过使用
[NSThread sleepforTimeInterval:30];
?Have you tried to use
[NSThread sleepforTimeInterval:30];
?sleep() 发生在主线程上,关联的运行循环永远没有机会调用计时器的选择器。
如果您在
-doSomething
中进行实际工作,并且不会阻塞线程,例如对 Web 服务的非阻塞调用,那么它将按预期工作。然而,阻塞调用必须在不同的线程中完成,这样主运行循环就不会被阻塞。The
sleep()
occurs on the main thread and the associated run loop never has the chance to invoke the selector for the timer.If you would do real work in
-doSomething
that doesn't block the thread, e.g. non-blocking calls to web-services, it would work as expected. Blocking calls however would have to be done in a different thread so the main run loop does not get blocked.