Подтвердить что ты не робот

IOS - данные процесса без замораживания пользовательского интерфейса

Мне нужно выполнить следующие задачи:

1) Прочитайте некоторые данные из базы данных sqlite

2) Обработать данные

3) Когда обработанные данные генерируют несколько диаграмм

Если у меня есть пользователь, который вводит множество данных в приложение, в один прекрасный день этот анализ может стать медленным и заморозить пользовательский интерфейс.

Итак, каков правильный способ его обработки, позволяющий пользователю взаимодействовать с пользовательским интерфейсом, с возможностью отмены операции или выхода из экрана?

Мне нужно сделать простые потоки для всех моих задач и с событием отмены или флагом, чтобы остановить их? Или есть еще один способ сделать это?

Например:

Задача 1: прочитать данные из sqlite в потоке с флагом, чтобы остановить процесс, если это необходимо.

Задача 2: Обработать данные в потоке с флагом, чтобы остановить процесс, если это необходимо.

Задача 3: Передача данных стороннему компоненту. На этом этапе его можно отменить операцию, выполняемую на другом компоненте?

Я думаю о правильном пути, или я мог бы что-то улучшить?

4b9b3361

Ответ 1

Это самый рекомендуемый и быстрый способ Apple с GCD (Grand Central Dispatch). Это также легче читать и понимать, потому что логика линейна, но не разделена между методами.

Обратите внимание, что он показывает слабый саунд-танец, который необходим, если асинхронный может пережить контроллер, к которому он вызван, поэтому он делает слабую ссылку на него, а затем проверяет, жив ли он и сохраняет его для обновления:

Swift 4 и 3.1

 DispatchQueue.global().async() {
      print("Work Dispatched")
      // Do heavy or time consuming work

      // Then return the work on the main thread and update the UI
      // Create weak reference to self so that the block will not prevent it to be deallocated before the block is called.
      DispatchQueue.main.async() {
           [weak self] in
           // Return data and update on the main thread, all UI calls should be on the main thread 
           // Create strong reference to the weakSelf inside the block so that it´s not released while the block is running
           guard let strongSelf = self else {return}
           strongSelf.method()
      }
 }

Objective-C

// To prevent retain cycles call back by weak reference
   __weak __typeof(self) weakSelf = self;  // New C99 uses __typeof(..)

    // Heavy work dispatched to a separate thread
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"Work Dispatched");
        // Do heavy or time consuming work
        // Task 1: Read the data from sqlite
        // Task 2: Process the data with a flag to stop the process if needed (only if this takes very long and may be cancelled often).

        // Create strong reference to the weakSelf inside the block so that it´s not released while the block is running
        __typeof(weakSelf) strongSelf = weakSelf;
        if (strongSelf) {

            [strongSelf method];

            // When finished call back on the main thread:
            dispatch_async(dispatch_get_main_queue(), ^{
                // Return data and update on the main thread
                // Task 3: Deliver the data to a 3rd party component (always do this on the main thread, especially UI).
            });
        }
    });

Swift 2.0 (см. новую версию выше)

  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
  print("Work Dispatched")
  // Do heavy or time consuming work

  // Create a weak reference to prevent retain cycle and get nil if self is released before run finishes
     dispatch_async(dispatch_get_main_queue()){
         [weak self] in
         // Task 3: Return data and update on the main thread, all UI calls should be on the main thread
            if let weakSelf = self {
               weakSelf.method()
            }
      }
  }

Способ отмены процесса состоит в том, чтобы включить значение BOOL и установить его для остановки из основного потока, если выполняемая работа больше не нужна. Но, возможно, это не стоит того, потому что пользователь не заметит фоновой работы так много, если не будет тяжелых вычислений. Для предотвращения циклов сохранения используйте слабые переменные, например:

__weak __typeof(self) weakSelf = self; // Obj-C
[weak self] in

и вызовите weakSelf с сильной ссылкой внутри блока (чтобы предотвратить сбои, если вызывающий VC был выпущен). Вы можете использовать точный тип типа UIViewController или функцию __typeof() (в C99 вам нужно использовать __typeof (..), но ранее вы могли напрямую использовать __typeof (..)), чтобы ссылаться на фактический тип:

Objective-C

__typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
   [strongSelf method];
}

Swift 3.1

if let weakSelf = self {
   weakSelf.method()
}

или

// If not referring to self in method calls.
self?.method()

ПРИМЕЧАНИЕ. Используйте GCD или Grand Central Dispatch, это самый простой способ, рекомендованный Apple, и поток кода находится в логическом порядке.

Ответ 2

вот как отделить функции от основной темы

[NSThread detachNewThreadSelector:@selector(yourmethode:) toTarget:self withObject:nil];