2016-10-26 2 views
4

Предположим, что я использую другой SDK (который я не контролирую) с API, который импортирует 1 файл асинхронно и вызывает завершение обратного вызова завершения при завершении. Ниже приведен пример API.Отказоустойчивый набор асинхронных операций с отчетностью о проделанной работе в iOS

func importFile(filePath: String, completion:() -> Void) 

Мне нужно импортировать 10 файлов (по одному), используя этот API, но мне нужно, чтобы это было сократимыми, например после того, как файлы 1,2,3 были успешно импортированы, в то время как файл 4 импортируется, я хочу иметь возможность отменить весь набор операций (импорт из 10 файлов), так что файл 4 будет завершен (поскольку он уже запущен), но Файлы 5-10 больше не будут импортированы.

Кроме того, мне также необходимо сообщить о ходе импорта. Когда файл 1 был успешно импортирован, я должен сообщить о ходе выполнения 10% (1 из 10 завершено).

Как я могу это достичь?

Я рассматриваю использование NSOperationQueue с использованием 10 NSOperations, но кажется, что отчет о проделанной работе будет затруднен.

+0

Пожалуйста, проверьте мой ответ и дайте мне знать, если это то, что вы ищете. – KrishnaCA

+0

На самом деле, я думаю, мы также можем использовать 'dispatch_suspend', чтобы решить эту проблему. Вы ищете решение, основанное только на NSOperation? – KrishnaCA

+0

Я отредактировал свой ответ таким образом, чтобы он отвечал на все ваши запросы. Я смиренно прошу вас взглянуть на него. – KrishnaCA

ответ

0

NSOperationQueue предлагает приятный объектный ориентированный абстарант и является тем, как я пойду.

  • Создать NSOperationQueue имени importQueue

Для каждого импорта:

  • Создать NSOperation
  • Хранить операцию, чтобы достичь и, возможно, CANCLE ней позже, например, в словаре [ImportNumber: NSOperation]
  • Добавить операцию в importQueue

Что касается состояния прогресса:

Вариант 1:

NSOperationQueue имеет свойство operations, whichs сосчитать вы можете наблюдать. (importQueue.operations.count).

Вариант 2:

NSOperation предлагает завершающие блоки. Вы можете увеличить счетчик при очередности операции и уменьшить ее в блоке завершения или при отмене.


Дальнейшее чтение: Apple documentation, asynchronous-nsoperation-why-and-how, nice but oldish tutorial.

+0

Как реализовать NSOperation для асинхронного API (как указано в описании проблемы)? –

+0

Конкретная реализация будет слишком длинной и imo. SO не собирается предлагать это. Если у вас есть вопросы после прочтения учебника, сообщите нам, возможно, в новом вопросе о конкретных новых проблемах, с которыми вы сталкиваетесь. – shallowThought

+0

Извините, я не прошу конкретной реализации. Краткий ответ в порядке. Вопрос явно указывает, что API (от стороннего SDK) является асинхронным, и ваш ответ использует синхронный API. –

0

Я думаю, вы должны добавить зависимости от вашей операции. Идея заключается в следующем:

1Op = NSOperation.. 
2Op = NSOperation.. 
. 
. 
10Op = NSOperation.. 

10Op.addDependency(9Op) 
9Op.addDependency(8Op) and so on... 

Тогда ваша операция подкласс должен переопределить метод отменить таким образом

cancel() { 
    super.cancel() 
    for dep in dependencies { 
     dep.cancel() 
    } 
} 
+0

Как насчет отчета о ходе выполнения и завершения обратного вызова? –

+0

Внутри вашей операции вы можете позвонить делегату обновления обновлений – iGenio

1

Итак, я считаю, что это следующее вы хотите от вашего вопроса:

  1. Импорт n файлов по очереди в очереди
  2. Отчет о ходе импорта каждого файла
  3. Возможность отмены операции в середине

Это может быть достигнуто с помощью NSOperationQueue и NSBlockOperation следующим образом.

  1. Создать AsyncBlockOperation и NSOperationQueue+AsyncBlockOperation классов из кода, приведенной в ответе на следующий StackOverflow вопрос: NSOperation wait until asynchronous block executes
  2. Импорт обоих классов в файл они собираются использовать
  3. Создание очереди операции

    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; 
    operationQueue.maxConcurrentOperationCount = 1; 
    operationQueue.name = @"com.yourOrganization.yourProject.yourQueue"; 
    
  4. Создать функцию, которая дает обратный вызов для достижения прогресса

    - (void)importFilesFromFilePathArray:(NSArray *)pathsArray 
            inOperationQueue:(NSOperationQueue *)operationQueue 
             withProgress:(void (^)(CGFloat progress))progressBlock { 
    
        } 
    
  5. Внутри функции, определенной в 2, используйте NSBlockOperation для выполнения ваших операций в NSOperationQueue

    for (int i = 0; i < pathsArray.count; i++) { 
    
        [operationQueue addAsyncOperationWithBlock:^(dispatch_block_t completionHandler) { 
         [self importFile:(NSString *)[pathsArray objectAtIndex:i] completion:^(bool completion) { 
          [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
           CGFloat progress = (100 * (float)(i+1)/pathsArray.count); 
           progressBlock(progress); 
           if (progress == 100) { 
            successBlock(YES); 
           } 
          }]; 
          completionHandler(); 
         }]; 
        }]; 
    } 
    
  6. Для отмены операции, мы можем просто использовать operationQueue, который мы создали в 1-ом этапе

    [operationQueue cancelAllOperations]; 
    

Я пробовал этот код mys Эльф. Он работает хорошо. Не стесняйтесь предлагать улучшения, чтобы сделать его лучше :)

+0

Выглядит хорошо. Но что вы будете делать, если * importFile * является асинхронным, как указано в описании проблемы? И как насчет завершения обратного вызова завершения, когда все операции были завершены, как вы справляетесь с этим требованием? –

+0

Я добавлю, что через несколько минут – KrishnaCA

+0

Если вы достигли успеха в 100, значит, это успешно. Здесь отчет о сбое становится затруднительным, если у вас есть возможность вручную отменить операции. Небольшое сомнение: если один из файлов импортируется, не удается, продолжаем или должны отменять все операции? – KrishnaCA

Смежные вопросы