【问题标题】:dispatch_after is limited to 10 seconds?dispatch_after 限制为 10 秒?
【发布时间】:2013-04-30 08:58:39
【问题描述】:

我正在开发一个在后台运行的应用程序。有时我需要告诉用户某事正在发生,所以我播放声音一定次数。为此,我制作了一个计时器,但问题是它不能超过总延迟时间的 10 秒,之后,不再有声音(但应用程序仍在运行)。我已经在前台模式下检查了这种行为,并且效果很好。

这是我需要通知用户时的代码:



    AudioServicesPlaySystemSound(alarma);
    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
    numAlarm = 1;  
    NSTimeInterval delay_in_seconds = 2.0;
    dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW,delay_in_seconds*NSEC_PER_SEC);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
    dispatch_after(delay,queue,^{
        [self fiBGTemps:ALARM];
    });

“fiBGTemps”是这样的,


- (void)fiBGTemps:(int)sender
{
    switch (sender){
        case TEMP_SCAN:
            (…)
            break;
        case ALARM:
            if (numAlarm>0 && numAlarm&ltNUM_ALARM)
            {
                AudioServicesPlaySystemSound(alarma);
                AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
                NSTimeInterval delay_in_seconds = 2;
                dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW,delay_in_seconds*NSEC_PER_SEC);
                dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
                dispatch_after(delay,queue,^{
                    [self fiBGTemps:ALARM];
                });
                numAlarm++;
            }
            break;
    }
}

这种行为正常吗?我错过了什么吗?

谢谢

卡尼克

【问题讨论】:

  • NUM_ALARM 设置为什么?也许这就是限制循环数量的原因。此外,这里似乎有两秒延迟的序列,而不是十秒延迟。
  • 嗨@aLevelOfIndirection,NUM_ALARM 是我设置用于测试该时间限制的常数(#define NUM_ALARM 20)。这样我就可以看到声音响了多少次。我测试的另一种方法是更改​​“delay_in_seconds”值。如果我将此值设置为 8(例如),它只会播放 2 种声音。如果我将此值设置为 12(大于 10),它只会播放一种声音。

标签: iphone objective-c background grand-central-dispatch


【解决方案1】:

问题解决了。

这就是发生的事情。当应用程序在后台运行并执行任务时,该任务也在后台运行,但系统只允许一定的时间(10 秒停机时间)以保护电池。所以它只适用于特定的任务(本地化、下载等)。

在我的情况下,我需要更多时间,因此解决方案是将任务定义为 UIBackgroundTask,这样该任务将在完成时通知系统,从而可以终止。

这是调用任务的代码:



    UIApplication *application = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier background_task;
    background_task = [application beginBackgroundTaskWithExpirationHandler: ^{
        [application endBackgroundTask: background_task];
        background_task = UIBackgroundTaskInvalid;
    }];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self fiBGTemps:@(ALARM)];
        [application endBackgroundTask: background_task];
        background_task = UIBackgroundTaskInvalid;
    });

在这里你可以看到苹果论坛上的讨论,他们比我解释得更好。

AppleForums discussion

我希望这会有所帮助。

卡尼克

【讨论】:

  • 你会在哪里添加延迟?
【解决方案2】:

您可以尝试在超过总延迟时间的10秒后重新设置延迟值,或者可能在播放声音一定时间后重新设置。

【讨论】:

  • 是的,这确实是我所做的。我已将延迟设置为 2 秒,并且(用于测试)重复超过 5 次(> 10 秒)。一旦达到 10 秒的时间,就没有更多的响应(这似乎是一个无限的时间)。所以我不能再这样做了。
  • 您能否分享将传递给 dispatch_after 的示例值 dispatch_after(delay,queue,^{ [self fiBGTemps:ALARM]; });需要知道这些变量(延迟和队列)存储了什么... dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW,delay_in_seconds*NSEC_PER_SEC); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
  • 嗨,@ManikantThakur,这是传递给 dispatch_after 的内容:delay_in_seconds = 8(使用此值它只播放一个声音),NSEC_PER_SEC 是在 clock_types.h 中声明的常量(#define NSEC_PER_SEC 1000000000ull ),队列和我在上面的代码中显示的一样,NUM_ALARM 是 15(这个值并不重要,重要的是 NUM_ALARM*delay_in_seconds > 10s 才能看到效果)。这是你要求的吗?
  • 好吧,每次在 delay_in_seconds 中传递 8 对你有用吗??如果是,你可以保持不变。正如您所说,因为在 delay_in_seconds 中传递 8 对您有用。如果你这样做,那么根据你的例子,它将大于 10s NUM_ALARM*delay_in_seconds > 10s 15 * 8 = 120。根据你的第一个响应,如果它达到 10s 时间,它不会响应。因此,尝试将 delay/repeat_time 的值重置为默认值。还要经常检查,以免超过 10。
  • 很抱歉,如果我在 5 月的最后评论中没有那么清楚。那8秒对我不好,它不起作用。我说8是为了复现,强求问题,看看是什么情况。我需要控制超过 10 秒的延迟(不是几分钟,而是超过 10 秒)。现在限制是 NUM_ALARM*delay_in_seconds = 10,我不知道为什么。
【解决方案3】:

我怀疑链接异步块以定期播放声音有点过头了。也许按照以下几行更简单的东西会更容易理解和维护:

// To initiate the alarm:
[self fiBGTemps: ALARM];

- (void)fiBGTemps:(int)sender
{
    switch (sender) {
       ...
       case ALARM:
           dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
                int count = 0;
                while (count < NUM_ALARM /* AND not interrupted by user? */) {
                    sleep(2);
                    AudioServicesPlaySystemSound(alarma);
                    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
                    count++;
                }
            });
            break;
        ...
    }
}

【讨论】:

  • 谢谢@aLevelOfIndirection。我刚刚尝试了您的方法,并且观察到了相同的结果。可能问题不在代码上(更干净或不在前台运行良好)。可能有一些配置参数或类似的东西。
  • 闹钟的声音文件有多长(以秒为单位)?
猜你喜欢
  • 1970-01-01
  • 2020-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 2014-03-27
  • 1970-01-01
相关资源
最近更新 更多