NSTimer 独特问题

发布于 2024-11-05 15:07:51 字数 3563 浏览 1 评论 0原文

我将直奔问题。

一周以来,这些都让我头疼。

我打算做的是设置我的计时器,该计时器应该从辅助线程在主运行循环上触发。所以我这样做。

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

路还长,别太狂 2024-11-12 15:07:51

您的代码中发生了一些有趣的事情:

  • 首先也是最重要的是,我至少 90% 肯定您不想在任何您的代码中调用 [[NSRunLoop mainRunLoop] run]程序的方法 - 这些方法是否退出,或者您是否继续在线程上聚合线程?
  • 其次,你的计时器失效有点奇怪:
    1. if (timerRefresh) if ([timerRefresh isValid]) [timerRefresh invalidate]; 中没有任何用处;;因为在 Objective C 中,消息传递 nil 是完全没问题的。此类消息的结果始终为 0x0,因此第一个 if 是不必要的,无论如何,在这种情况下第二个 if 的计算结果为 NO
    2. 使计时器无效意味着将其从预定的运行循环中删除。因此,第二个 if 也是不必要的 - 只剩下 [timerRefresh invalidate];
    3. 要使 -[NSTimer invalidate] 生效,需要在调度计时器的线程上调用它。据我了解,您的所有方法并非都是如此。因此,您应该使用带有适当参数的 performSelectorOnMainThread:withObject:waitUntilDone:
  • [self PerformSelector:@selector(sendTeamNameClickToFunction:) withObject:sender] 和简单的 [self sendTeamNameClickToFunction:sender] 之间没有区别。只是后者更容易阅读;-)
  • pauseAndResumeTimer: 中的 if 子句没有多大意义,即有很多代码重复。

这是一种整理方式的方法,并且失效发生在主线程上:

-(void)pauseAndResumeTimer:(NSNotification *)notification
{
    [timerRefresh performSelectorOnMainThread:@selector(invalidate) withObject:nil waitUntilDone:YES];
    timerRefresh = nil;

    NSNumber *result = [notification object];
    if ([result boolValue]) return;

    if ( !self.isConnectionAvailable || 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 mainRunLoop] addTimer:timerRefresh forMode:NSDefaultRunLoopMode];
}

There is some funny stuff going on in your code:

  • First and formemost, I am at least least 90% positively sure that you don't want to call [[NSRunLoop mainRunLoop] run] in any of your program's methods — do those methods even exit, or do you keep aggregating thread upon thread?
  • Secondly, your timer invalidations are all a bit strange:
    1. There is no use in if (timerRefresh) if ([timerRefresh isValid]) [timerRefresh invalidate];; since in Objective C, messaging nil is perfectly fine. The result of such a message is always 0x0, so the first if is unnecessary and the second one evaluates to NO in that case, anyway.
    2. Invalidating a timer means removing it from the runloop it was scheduled on. Hence, the second if is unnecessary, too — leaving you with just [timerRefresh invalidate];.
    3. For -[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 use performSelectorOnMainThread:withObject:waitUntilDone: with the appropriate arguments instead.
  • There is no difference between [self performSelector:@selector(sendTeamNameClickToFunction:) withObject:sender] and simply [self sendTeamNameClickToFunction:sender]. Except that the latter is much easier to read ;-)
  • The if clauses in pauseAndResumeTimer: 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:

-(void)pauseAndResumeTimer:(NSNotification *)notification
{
    [timerRefresh performSelectorOnMainThread:@selector(invalidate) withObject:nil waitUntilDone:YES];
    timerRefresh = nil;

    NSNumber *result = [notification object];
    if ([result boolValue]) return;

    if ( !self.isConnectionAvailable || 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 mainRunLoop] addTimer:timerRefresh forMode:NSDefaultRunLoopMode];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文