Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 理解后台任务执行语法和GCD_Ios_Objective C_Uikit_Grand Central Dispatch_Background Process - Fatal编程技术网

Ios 理解后台任务执行语法和GCD

Ios 理解后台任务执行语法和GCD,ios,objective-c,uikit,grand-central-dispatch,background-process,Ios,Objective C,Uikit,Grand Central Dispatch,Background Process,我正在努力完全理解下面的代码,我是在研究了iOS中的后台任务后编写的,希望能得到一些帮助 我理解基本概念 首先,我们获取应用程序单例,然后创建一个块并向系统注册后台任务,最后异步调度任务以运行 以下是我寻求帮助的部分: 当后台任务被分配到块时,实际块中没有我们想要在其中运行的代码,只有它的完成处理程序中的清理代码,这是为什么 我知道dispatch\u async基本上启动一个新线程并开始处理块中的代码,但是在这个dispatch\u async请求中,后台任务引用在哪里?我不明白系统是如何理解

我正在努力完全理解下面的代码,我是在研究了iOS中的后台任务后编写的,希望能得到一些帮助

我理解基本概念

首先,我们获取应用程序单例,然后创建一个块并向系统注册后台任务,最后异步调度任务以运行

以下是我寻求帮助的部分:

  • 当后台任务被分配到块时,实际块中没有我们想要在其中运行的代码,只有它的完成处理程序中的清理代码,这是为什么

  • 我知道dispatch\u async基本上启动一个新线程并开始处理块中的代码,但是在这个dispatch\u async请求中,后台任务引用在哪里?我不明白系统是如何理解我们希望在dispatch\u async请求中执行的代码与我们先前注册的后台任务相关的

  • 为什么在分派异步块的末尾和后台任务的完成处理程序中都需要清理代码

  • 抱歉,如果这些问题很愚蠢,我只是不懂语法

    以下是我拼凑的代码:

    UIApplication *application = [UIApplication sharedApplication]; //Get the shared application instance
    
    __block UIBackgroundTaskIdentifier background_task; //Create a task object
    
    background_task = [application beginBackgroundTaskWithExpirationHandler: ^ { //Register background_task    
                    [application endBackgroundTask: background_task]; //Tell the system that we are done with the tasks
                    background_task = UIBackgroundTaskInvalid; //Set the task to be invalid
                    //Above code called when endBackgroundTask is called
                }];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    //Perform your tasks that your application requires
    
                    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateText) userInfo:nil repeats:YES];
                    NSLog(@"\n\nRunning in the background!\n\n");
    
                    [application endBackgroundTask: background_task]; //End the task so the system knows that you are done with what you need to perform
                    background_task = UIBackgroundTaskInvalid; //Invalidate the background_task
                });
    

    后台任务标识符与您在辅助线程上所做的工作之间没有关系。后台任务代表一个额外运行时间的请求。这就是全部。你需要结束它,告诉操作系统你已经完成了你想做的工作。如果您未能在可用时间内完成此操作,您的应用程序将被终止。任务ID只是一个令牌,表示操作系统允许它继续工作一段时间

    您必须在两个位置进行清理,即过期处理程序和异步调度块的末尾,因为它们代表两个不同的事件。在您分派到并发队列的块中,您结束了任务,因为您及时完成了工作,并且希望让操作系统知道,以便它可以挂起您的应用程序;它不需要终止它。在过期处理程序中,这是结束任务以防止应用程序终止的最后机会。你还没有完成工作,但时间不够了。如果你当时没有结束后台任务,操作系统会杀死你的应用程序


    顺便说一下,在调度队列上运行的任务中调度计时器将不起作用。在线程的运行循环中安排计时器。可以随时终止服务调度队列的工作线程,并且在任何情况下都不会运行其运行循环。

    为了清楚起见,我将后台任务设置为:

    @interface myClass ()
        @property (nonatomic, assign) UIBackgroundTaskIdentifier backgroundUpdateTask;
    @end
    
    - (void)importantStuffToCompleteInBackground
    {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
        ^{
            [self beginBackgroundUpdateTask];
    
            // do important background stuff
    
            [self endBackgroundUpdateTask];
        });
    }
    
    - (void)beginBackgroundUpdateTask
    {
        self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
            [self endBackgroundUpdateTask];
        }];
    }
    
    - (void)endBackgroundUpdateTask
    {
        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundUpdateTask];
        self.backgroundUpdateTask = UIBackgroundTaskInvalid;
    }
    

    根据本文,如果您没有通过调用dispatch_async中的
    endBackgroundTask
    及时完成重要的后台工作代码块,则仅在剩余后台时间达到0之前不久才会调用该块。

    您的应用程序中可能随时都有各种长时间运行的后台任务时间有几种方法可以运行后台任务

    或者你可以使用看起来很简单的

    dispatch_async( queue, ^{
     [self saveAllUserDataToServer];
    } );
    
    但不要被愚弄,任何涉及多线程的事情都是困难和危险的。这是一个大问题,从你的问题中不清楚你是否有具体的任务要做,你想得到帮助

    其中一个危险是,用户或系统可以随时停止您的应用程序。您已经开始的后台任务可能已经完成了一半,然后就停止了。这可能是一场灾难,也可能只是不方便

    iOS提供了一种不让这些任务突然停止的方法。无论何时开始这样一项任务,都必须让系统知道,然后在任务完成时告诉它,就像这样

    - (void)saveAllUserDataToServer {
      UIBackgroundTaskIdentifier bt = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^ {}];
      ... do the work ...
      [application endBackgroundTask: background_task];
    }
    
    …现在您知道,在后台线程上调用
    -saveAllUserDataToServer
    是安全的,即使应用程序中途关闭,它也会一直运行到完成

    需要注意的一点是,完成任务只有一定的时间限制。。如果花费的时间太长,将调用ExpirationHandler块,您必须在此处正确清理。这是设置代码更像的方式

    __block UIBackgroundTaskIdentifier bt = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^ {
        .. task didn't complete within time limit.. do additional cleanup
        [[UIApplication sharedApplication] endBackgroundTask: background_task];
    }];
    

    这个问题似乎已经很久没有被问到和回答了。 我只想在这里做一个说明,因为我感觉用户Woodstock(可能是我们中的很多人)对“后台线程”和“后台任务”有点困惑

    • “后台线程”是在UI线程和后台线程的上下文中考虑的

    • “后台任务”是在允许比正常持续时间(iOS中为10秒)更长的任务上下文中考虑的。 方法
      beginBackgroundTaskWithExpirationHandler
      :告诉iOS,如果应用程序是后台的,你需要更多的时间来完成你正在做的事情(请参考应用程序的生命周期概念)。在这次调用之后,如果你的应用程序是后台的,它仍然会得到CPU时间,直到你调用
      endBackgroundTask
      :或者系统发出它将过期的信号


    当我的应用程序转到后台时,由于后台有一个持续运行的进程,我遇到了以下错误:

    无法结束BackgroundTask:不存在标识符为9的后台任务,或者它可能>已结束。中断UIApplicationEndBackgroundTaskError()以进行调试

    谢天谢地,我偶然发现了hooleyhoop的答案,并且我能够通过下面的代码示例绕过它:

    func run() {
      DispatchQueue(label: "ping").async {
        let tid = UIApplication.shared.beginBackgroundTask(withName: "ping", expirationHandler: {})
        //network code
        //save data to database code
        UIApplication.shared.endBackgroundTask(tid)      
        run() //repeat process
      }
    }
    
    您还可以使用:

    UIApplication.shared.beginBackgroundTask(expirationHandler:{}) 
    

    如果您在调试时不需要一个好名字

    您想要有人解释您编写的代码吗?@hooleyhoop,不,我想要有人帮助解释我明确表示的“拼凑”在一起的代码的更详细的细节,但感谢您的输入。我想知道您是否真的知道您正在尝试做什么。“后台任务”是用户切换到其他应用程序时执行的任务,通常应避免。他们什么也没做