DispatchQueue.global(qos: .default) продолжается, когда приложение находится в фоновом режиме или экран заблокирован, как приостановить?

Swift Newbie: перенос кода интеграции Objective-C AppleHealth на Swift, который вызывается Flutter/Dart. Когда я запускаю устаревшее приложение Obj-C в фоновом режиме или блокирую экран, оно почти сразу же приостанавливает все выполнение. Однако такое же поведение не происходит в моем порте кода Swift, я использую тот же DispatchQueue в Swift, что и в устаревшем приложении Obj-C,

Причина, по которой важно приостановить работу, заключается в том, что как только пользователь блокирует экран iPhone, AppleHealth шифрует все свои данные и становится недоступным. Также я правильно понимаю, что когда вы приостанавливаете DispatchQueue, текущий исполняемый блок будет завершен, но последующие блоки не начнут выполнение. Насколько я могу судить, мой порт кода Swift имитирует логику Obj-C, любые подсказки относительно того, почему он ведет себя по-другому или что мне может не хватать, будут очень признательны.

я отправляю с помощью

DispatchQueue.global(qos: .default).async { 
/* code */ 
}

Если бы новое приложение могло немедленно приостановить весь исполняемый код, который я отправил в DispatchQueue, в фоновом режиме или на экране блокировки, я был бы очень счастлив.


person Random Joe    schedule 01.04.2019    source источник
comment
Вы не можете приостановить выполнение DispatchQueue задач. Если вам нужно больше контроля, вы должны использовать OperationQueue. Это основное различие между ними: если что-то написано внутри блока DispatchQueue, эта задача будет выполнена в какой-то момент.   -  person Sharad Chauhan    schedule 01.04.2019
comment
@SharadChauhan - Очереди операций в этом отношении не отличаются от пользовательских очередей отправки. Если ваше приложение все еще работает, приостановка очереди также не приведет к приостановке операций, выполняемых на OperationQueue. Когда вы приостанавливаете очередь операций, это только предотвращает запуск новых операций. Но выполняемые операции не приостанавливаются.   -  person Rob    schedule 01.04.2019


Ответы (1)


Когда приложение приостанавливается, все, что выполняется, будь то в основной очереди или в фоновой global очереди, также приостанавливается.

Делаете ли вы что-нибудь в приложении, чтобы оно работало в фоновом режиме? Например, если вы запускаете приложение через отладчик Xcode (например, чтобы вы могли просматривать свои операторы print или что-то еще), это изменяет жизненный цикл приложения и поддерживает его работу в фоновом режиме. («Эффект наблюдателя» в Xcode? Lol.) Например. вы запускаете это через отладчик Xcode?

Кроме того, если в вашем приложении включены определенные фоновые возможности, это также может поддерживать работу приложения.

Поскольку вы не можете запустить приложение через отладчик Xcode, чтобы наблюдать за жизненным циклом приложения, я продемонстрирую процесс, используя Унифицированное ведение журнала для отслеживания хода выполнения моего приложения. С помощью Unified Logging я могу отслеживать эти операторы журнала на своем iPhone с консоли macOS, даже не запуская Xcode.

Рассмотрим что-то вроде:

import UIKit
import os.log

private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "ViewController")

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        os_log("viewDidLoad", log: log, type: .debug)
        startTask()
    }

    func startTask() {
        DispatchQueue.global().async {
            var i = 0
            while true {
                let start = Date()
                while Date().timeIntervalSince(start) < 1 { }
                os_log("tick %d", log: log, type: .debug, i)
                i += 1
            }
        }
    }
}

(Обратите внимание, как правило, вы никогда не должны вращаться таким образом, но я сделал это, чтобы иметь процесс, который намеренно загружает ЦП.)

Итак, я тогда:

  • установлен на моем устройстве,
  • выйти из Xcode,
  • запустил консольное приложение macOS,
  • в консольном приложении я включил ведение журнала отладки с помощью «Действие» » «Включить сообщения отладки»,
  • отфильтровать журнал, чтобы я видел активность только из своей подсистемы (лично я всегда использую для этого идентификатор пакета), и
  • запустить мое приложение прямо на моем устройстве iOS.

Мы ясно видим, что приложение останавливается (включая эту задачу, работающую в фоновой очереди), когда я приостанавливаю приложение. (Очевидно, что в дополнение к сообщениям os_log, приведенным выше, я поместил аналогичные операторы в свой AppDelegate, чтобы я мог видеть и события жизненного цикла здесь.) Во всяком случае, вот что показала моя консоль:

Консоль

Я вышел из своего приложения, когда появился «тик 5», потребовалось несколько секунд, прежде чем приложение было полностью приостановлено, но вы можете видеть, что приложение перестало работать после появления «тика 7» и «applicationDidEnterBackground». И я перезапустил приложение примерно через 10 секунд, и в этот момент вы видите, что приложение возвращается к жизни и возобновляет работу с того места, где остановилось.

Итак, если ваше приложение все еще работает, оно либо подключено к отладчику Xcode, либо у вас есть что-то, что поддерживает работу приложения в фоновом режиме. Но обычно, когда вы выходите из приложения, оно приостанавливается, и вы увидите поведение, описанное выше.

Кстати, для получения дополнительной информации об использовании единого ведения журнала, настройке устройства и т. д. см. видео WWDC 2016 Единое ведение журнала и отслеживание действий.

person Rob    schedule 01.04.2019
comment
Большое спасибо, Роб, я не знал об унифицированном ведении журналов, это как раз то, что мне нужно, чтобы увидеть жизненный цикл. - person Random Joe; 08.04.2019