2013-09-16 4 views
3

У меня есть процесс с 3 шагами. Каждый из них должен быть выполнен до другого (синхронный, последовательный и т. Д.). Все они должны быть выполнены в фоновом режиме, чтобы не блокировать пользовательский интерфейс.Добавить блок в очередь с addOperationWithBlock и использовать блок завершения

Я пытаюсь немного перестроить вещи, чтобы использовать 2 очереди, один для сетевых операций, один для обновлений db для защиты основных данных. Подпрыгивая назад и вперед между очередями, я могу держать вещи серийными, просто отбирая блок, а затем, когда это называется, что-то получится.

Я использую addOperationWithBlock для создания операции и вставки в нее, но не вижу очевидного способа сделать блок завершения (например, я делаю это с помощью setCompletionBlock). Я не уверен, как начать второй шаг, когда это будет сделано. Я перепробовал его, и я просто вызываю следующий метод (отправную точку для шага 2) в конце блока для шага 1? Проблема в том, что внутри этих блоков могут быть асинхронные вызовы AFNetworking.

вот код и дополнительная информация. Я хочу попасть на сервер, захватить данные, то по завершении выполнения что-то другое, но связать их так, он должен перейти от данных к верификации шага серийно:

self.networkQueue = [NSOperationQueue new]; 
self.networkQueue.maxConcurrentOperationCount = 1; 
self.databaseQueue = [NSOperationQueue new]; 
self.databaseQueue.maxConcurrentOperationCount = 1; 

[self.networkQueue addOperationWithBlock:^{ 

     NSString *listURL = [NSString stringWithFormat:GET_LIST,BASE_URL]; 
     NSURL *url = [NSURL URLWithString:briefListURL]; 
     NSURLRequest *request = [NSURLRequest requestWithURL:url]; 

     AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest: request 
                          success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { 
                           self.list = [NSArray arrayWithArray:(NSArray *)JSON];                          
                          } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) { 
                           [self listOperationDidFail]; 
                          }]; 

     // define block that will execute when the task is finished 
     [operation setCompletionBlock:^{ 
      // Latest data retrieved. Check if db needs updating 
      [self verifyList]; 
     }]; 

     [operation start]; 
    }]; 

ответ

1

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

- (void)doThreeAsynchThingsSeriallyThenInvoke:(void (^)(void))finished { 

    [self doTheFirstThingThenInvoke:^(id result, NSError *error) { 
     if (!error) { 
      [self doTheSecondThingWith:result thenInvoke:^(BOOL success) { 
       [self doThLastThingThenInvoke:finished]; 
      }]; 
     } 
    }]; 
} 

Edit - Для дальнейшей разработки, скажем doTheFirstThing о делает сетевой вызов, то разборе результат:

- (void)doTheFirstThingThenInvoke:(void (^)(id, NSError *))finished { 

    NSURLRequest *request = // form a request, etc. 
    [NSURLConnection sendAsynchronousRequest:request queue:someQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 
     id parsed = nil; 
     if (!error) { 
      parsed = // parse the result contained in NSData *data 
     } else { 
      // handle error 
     } 
     // here's the important part: invoke the completion block either way 
     // it will get either nil and an error, or a parsed result and nil 
     finished(parsed, error); 
    }]; 
} 

... и скажем, что doTheSecondThing для хранения данных в базе данных:

- (void)doTheSecondThingWith:(id)parsedData thenInvoke:(void (^)(BOOL))finished { 

    // you can do something asynch here, maybe on an operation queue 
    // or some other way off the main. Let's say it's an animation, because 
    // that takes a BOOL block and we can demonstrate just passing our 
    // block param along 

    [UIView animateWithDuration:3.0 
        animations:^{ self.someView.alpha = 0.0 } 
        completion:finished]; 

    // see? we passed the finished block directly to the animation 
    // it will be invoked after the animation is complete 

В итоге, первый (запрос сети) произошла асинхронный, от основных, и вызывается блок, когда это было сделано , Блок вызывал вторую вещь (анимацию), которая передавала ее блок в действие aysnch. Третья вещь начнется только после того, как будет запрошен сетевой запрос, и анимация (которая обе сработала с основного) завершена.

+0

привет, спасибо за ответ, я действительно ценю это. Я обновил свой пост с помощью некоторого кода.пытаясь понять пример вложенности, который вы вставили, и я не совсем понимаю, извините. поэтому doTheFirstThingThenInvoke будет иметь фактический код первой вещи, и этот вызов знает, чтобы вызвать блок (вторая вещь), когда это было сделано? если первая вещь содержит асинхронный вызов, как она не возвращается и начинает вторую вещь после отключения асинхронного вызова? – skinsfan00atg

1

Настоящая проблема заключается в асинхронном процессе в блоке завершения блока в очереди.

Этот рецепт поможет:

  1. Создать экземпляр NSOperationQueue. Set maxConcurrentOperationCount = 1.

  2. Объявите все блокирующие процессы и их блоки завершения. Поместите туда что угодно. В начале каждого блочного процесса поместите фрагмент кода, который приостанавливает создание NSOperationQueue. В конце блока завершения каждого блока поместите фрагмент кода, который не подпускает одну и ту же очередь - если вы вызываете асинхронный процесс внутри своего блока или его блока завершения, вам нужно поместить/вызвать этот unsuspending код в конце этого асинхронного процесса.

  3. Добавьте все свои блоки в NSOperationQueue.

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

+0

Большое спасибо за ответ! Я редактировал свой пост с кодом. и я def пытался использовать opqueues и max count. так что для блоков завершения, как это сделано выше, это правильно с setCompletionBlock в операции? проблема заключается в том, когда я запускаю, когда он ударяет по этому блоку завершения, прежде чем он ударит по блоку успеха или отказа, как это возможно? – skinsfan00atg

+0

Я отредактировал ваш код. Код не проверен, но должен работать хорошо. Если вы вызываете другую асинхронную операцию внутри вашей асинхронной операции, которая уже находится в очереди на работу, очередь не будет «ждать» для вашей операции async в этом блоке. Другими словами, вы можете выполнять только синхронный код внутри одного операционного блока в очереди. Вот почему я предложил приостановить очередь. – ArturOlszak

+0

еще раз спасибо! ive попробовал setCompletionBlock, но мой код добирается до этого кода, прежде чем он когда-либо попадет в код успеха или отказа, как это произойдет? – skinsfan00atg

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