NSTimer 独特问题
我将直奔问题。
一周以来,这些都让我头疼。
我打算做的是设置我的计时器,该计时器应该从辅助线程在主运行循环上触发。所以我这样做。
if(timerRefresh)
{
//[timerRefresh invalidate];
timerRefresh = nil;
}
if (!self.isConnectionAvailable) {
timerRefresh = [NSTimer timerWithTimeInterval:appDelegate.TimerInterval target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
else if (self.isLivePresent||self.isUpcomingMatchToday) {
timerRefresh = [NSTimer timerWithTimeInterval:appDelegate.TimerInterval target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
else {
timerRefresh = [NSTimer timerWithTimeInterval:LongRefresh target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
[runLoop addTimer:timerRefresh forMode:NSDefaultRunLoopMode];
[runLoop run];
当它触发时,加载器开始在主线程上加载,并且处理工作在辅助线程上完成。
我希望这是一个正确的方法。
现在我在这个主类中有一个子类,它在触发过滤过程时还必须显示一个加载器,因此为了避免多个加载器,当过滤过程触发时,我通过向其发送通知来暂停父类的刷新来自子类..像这样...
-(void)teamNameClicked:(id)sender
{
BOOL result = YES;
NSNumber *newNumber = [NSNumber numberWithBool:result];
[[NSNotificationCenter defaultCenter] postNotificationName:@"PauseMatchesLiveMatchTimer" object:newNumber];
[self performSelector:@selector(sendTeamNameClickToFunction:) withObject:sender];
}
当操作完成时,我有另一个通知器,如下所示...
-(void)processTeamNameClick:(id)sender
{
UIButton *button = (UIButton *)sender;
selectedIndexDropDown = button.tag;
[self parseTeamFile:button.tag];
self.lblDropDown.text = [dictTeamFilter valueForKey:[NSString stringWithFormat:@"%i",button.tag]];
[tblResults performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
BOOL result = NO;
NSNumber *newNumber = [NSNumber numberWithBool:result];
[[NSNotificationCenter defaultCenter] postNotificationName:@"PauseMatchesLiveMatchTimer" object:newNumber];
}
注意结果的“是”和“否”..
现在这是通知的观察者...
-(void)pauseAndResumeTimer:(NSNotification *)notification;
{
NSNumber *newNumber = [notification object];
BOOL result = [newNumber boolValue];
if (result) {
if(timerRefresh)
{
if ([timerRefresh isValid])
[timerRefresh invalidate];
timerRefresh = nil;
}
}
else
{
if(timerRefresh)
{
if ([timerRefresh isValid])
[timerRefresh invalidate];
timerRefresh = nil;
}
if (!self.isConnectionAvailable) {
timerRefresh = [NSTimer timerWithTimeInterval:appDelegate.TimerInterval target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
else if (self.isLivePresent||self.isUpcomingMatchToday) {
timerRefresh = [NSTimer timerWithTimeInterval:appDelegate.TimerInterval target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
else {
timerRefresh = [NSTimer timerWithTimeInterval:LongRefresh target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
[runLoop addTimer:timerRefresh forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
当过滤过程开启时,我停止父计时器。当关闭时我会再次启动它。
好吧...现在的问题...当我在页面上进行正常导航时,它工作得非常好...比如切换选项卡、在页面之间遍历等。
但是如果我使用过滤过程,不知何故,它会触发我的计时器主页,甚至当视图消失时,似乎都会启动我的计时器事件。我想避免这种情况,但我只是不知道如何......
如果有人能真正帮助我,请这样做。 提前致谢。
I'll go straight to the problem.
This ones eating my head since a week.
What i intend to do is set my timer, which is supposed to be fired on main run loop, from a secondary thread. So i do it as follows.
if(timerRefresh)
{
//[timerRefresh invalidate];
timerRefresh = nil;
}
if (!self.isConnectionAvailable) {
timerRefresh = [NSTimer timerWithTimeInterval:appDelegate.TimerInterval target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
else if (self.isLivePresent||self.isUpcomingMatchToday) {
timerRefresh = [NSTimer timerWithTimeInterval:appDelegate.TimerInterval target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
else {
timerRefresh = [NSTimer timerWithTimeInterval:LongRefresh target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
[runLoop addTimer:timerRefresh forMode:NSDefaultRunLoopMode];
[runLoop run];
When this fires, a loader begins loading on the main thread, and the processing work is done on the secondary thread.
I hope this is a correct way.
Now i have a child class within this main class which also has to show a loader while it triggers a filtering process, so to avoid multiple loaders, when the the filtering process triggers, i pause the refreshing on this parent class, by sending it notifications from the child class..like this...
-(void)teamNameClicked:(id)sender
{
BOOL result = YES;
NSNumber *newNumber = [NSNumber numberWithBool:result];
[[NSNotificationCenter defaultCenter] postNotificationName:@"PauseMatchesLiveMatchTimer" object:newNumber];
[self performSelector:@selector(sendTeamNameClickToFunction:) withObject:sender];
}
and when operation completes i have another notifier as this...
-(void)processTeamNameClick:(id)sender
{
UIButton *button = (UIButton *)sender;
selectedIndexDropDown = button.tag;
[self parseTeamFile:button.tag];
self.lblDropDown.text = [dictTeamFilter valueForKey:[NSString stringWithFormat:@"%i",button.tag]];
[tblResults performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
BOOL result = NO;
NSNumber *newNumber = [NSNumber numberWithBool:result];
[[NSNotificationCenter defaultCenter] postNotificationName:@"PauseMatchesLiveMatchTimer" object:newNumber];
}
Notice the YES and NO for results..
Now this is an observer for the notification...
-(void)pauseAndResumeTimer:(NSNotification *)notification;
{
NSNumber *newNumber = [notification object];
BOOL result = [newNumber boolValue];
if (result) {
if(timerRefresh)
{
if ([timerRefresh isValid])
[timerRefresh invalidate];
timerRefresh = nil;
}
}
else
{
if(timerRefresh)
{
if ([timerRefresh isValid])
[timerRefresh invalidate];
timerRefresh = nil;
}
if (!self.isConnectionAvailable) {
timerRefresh = [NSTimer timerWithTimeInterval:appDelegate.TimerInterval target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
else if (self.isLivePresent||self.isUpcomingMatchToday) {
timerRefresh = [NSTimer timerWithTimeInterval:appDelegate.TimerInterval target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
else {
timerRefresh = [NSTimer timerWithTimeInterval:LongRefresh target:self selector:@selector(startAutoRefresh) userInfo:nil repeats:NO];
}
NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
[runLoop addTimer:timerRefresh forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
When the filtering process is on, i stop the parent timer. And when off i start it again.
Ok...So now the problem... When i do normal navigation on my pages, it works absolutely fine..like switching tabs, traversing between pages etc.
But if i use the filter process, somehow, it triggers my timer on the main page, and even when the view has disappeared, seems to kick off my timer event. I want to avoid that, but i just dont know how..
If anyone can genuinely help me, please do.
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的代码中发生了一些有趣的事情:
[[NSRunLoop mainRunLoop] run]
程序的方法 - 这些方法是否退出,或者您是否继续在线程上聚合线程?nil
是完全没问题的。此类消息的结果始终为0x0
,因此第一个if
是不必要的,无论如何,在这种情况下第二个if
的计算结果为NO
。if
也是不必要的 - 只剩下[timerRefresh invalidate];
。-[NSTimer invalidate]
生效,需要在调度计时器的线程上调用它。据我了解,您的所有方法并非都是如此。因此,您应该使用带有适当参数的performSelectorOnMainThread:withObject:waitUntilDone:
。[self PerformSelector:@selector(sendTeamNameClickToFunction:) withObject:sender]
和简单的[self sendTeamNameClickToFunction:sender]
之间没有区别。只是后者更容易阅读;-)pauseAndResumeTimer:
中的if
子句没有多大意义,即有很多代码重复。这是一种整理方式的方法,并且失效发生在主线程上:
There is some funny stuff going on in your code:
[[NSRunLoop mainRunLoop] run]
in any of your program's methods — do those methods even exit, or do you keep aggregating thread upon thread?if (timerRefresh) if ([timerRefresh isValid]) [timerRefresh invalidate];
; since in Objective C, messagingnil
is perfectly fine. The result of such a message is always0x0
, so the firstif
is unnecessary and the second one evaluates toNO
in that case, anyway.if
is unnecessary, too — leaving you with just[timerRefresh invalidate];
.-[NSTimer invalidate]
to have an effect, it needs to be called on the thread the timer is scheduled on. From what I understood, this is not the case in all your methods. So you should useperformSelectorOnMainThread:withObject:waitUntilDone:
with the appropriate arguments instead.[self performSelector:@selector(sendTeamNameClickToFunction:) withObject:sender]
and simply[self sendTeamNameClickToFunction:sender]
. Except that the latter is much easier to read ;-)if
clauses inpauseAndResumeTimer:
don't make an awful lot of sense, i.e. there's a lot of code duplication.Here is said method in a tidied-up fashion and with the invalidation happening on the main thread: