iOS 4 GCD вопросы - PullRequest
       11

iOS 4 GCD вопросы

6 голосов
/ 27 июля 2010

Я посмотрел некоторые из презентаций WWDC 2010, а также прочитал большинство документов по блокам и параллелизму и у меня есть пара вопросов, касающихся использования блоков с последовательными очередями в Grand Central Dispatch. У меня есть проект iOS 4, у которого есть прокрутка и словарь информации об изображениях - ссылки на изображения и так далее. Я хочу использовать GCD и блоки для загрузки изображений и помещать их в мой скролл-просмотр, таким образом, не блокируя основной поток. Я написал следующий код, который, кажется, работает:

for (NSDictionary* dict in images)
{
     dispatch_async(image_queue, ^{

           NSString* urlString = [dict objectForKey:@"url"];
           NSURL* url = [NSURL URLWithString:urlString];
           NSData* imageData = [[NSData alloc] initWithContentsOfURL:url];
           UIImage* image = [UIImage imageWithData:imageData];
           UIImageView* imageView = // initialize imageView with image;      

           dispatch_async(dispatch_get_main_queue(), ^{
                [self.scrollView addSubview:imageView];
           });
           [imageData release];
      });
}

У меня два вопроса:

  1. Согласно руководству по параллелизму, я не должен захватывать переменные из охватывающей области, которые не являются скалярными типами - в моем коде я фиксирую dict, который является объектом NSDictionary *. Если мне не разрешено захватить это, как я тогда должен написать код? Захватывает ли блок только те переменные из области действия, которые фактически используются?

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

С уважением,

Ответы [ 5 ]

10 голосов
/ 10 августа 2010
  1. Несмотря на то, что это непростая задача, важно понять, что руководство по параллелизму пытается вам сказать: указатели являются скалярными типами. Таким образом, вы можете захватывать указатели внутри блоков все, что вы хотите ... НО вы должны быть осведомлены о времени жизни памяти, на которую они указывают! NSDictionary * is-a-kind-of id, и когда вы ссылаетесь на id в блоке, среда выполнения берет на себя ответственность за сохранение идентификатора, если блок копируется (что делается с помощью dispatch_async ()), а затем освобождает его, когда блок Сам по себе освобожден. И да, блок захватывает только переменные, на которые есть ссылки.

  2. Поскольку теперь вы знаете, что асинхронный блок выполнил сохранение на себя, должно быть ясно (э), что (по модулю ошибки управления памятью) ваш ViewController не может «исчезнуть», пока блок не будет выполнен. Так что это не приведет к сбою - но вы правильно заметили, что вы действительно хотите отменить асинхронную работу такого рода, когда вы на самом деле больше не планируете использовать результаты. Один простой, но эффективный шаблон - поместить в начало вашего асинхронного блока тест, который проверяет, должна ли работа все еще выполняться.

3 голосов
/ 27 сентября 2011

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

Попробуйте использовать NSOperationQueue со значением maxConcurrentOperationCount, равным 2 или 3. Это позволит вам ставить в очередь потенциально бесконечное количество сетевых запросов, но не более нескольких из них будут работать параллельно. Поскольку вы можете получить доступ к сетевому состоянию устройства, вы можете условно увеличить его, например, до 8 для подключений Wi-Fi.

И вторая проблема, связанная с GCD, заключается в том, что отменить ожидающие операции немного громоздко. Если ваш пользователь входит в контроллер представления и затем отодвигается назад, в зависимости от того, как вы запрограммировали свой код, блоки GCD сохранят контроллер представления, предотвратят его отпускание, и фактически все сетевые операции должны будут завершиться, пока контроллер не будет освобожден (поэтому нет смысла отменять соединения в dealloc).

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

tl; dr использовать очередь для сети, GCD для обработки изображений / масштабирования / обновления графического интерфейса.

1 голос
/ 26 сентября 2011

@ Kaelin Colclasure: для 1-го вопроса представляется более вероятной проблема общего состояния в многопоточном приложении: для целочисленного типа у вас есть копия по значению (что также относится к указателям), но когда вы будете использовать объект, на который ссылаетсяУказатель, у вас будут все проблемы, связанные с отсутствием блокировки (разновидность проблемы времени жизни объекта, которую вы упомянули здесь).

0 голосов
/ 28 ноября 2018

Существуют некоторые ограничения и требования, которые следует учитывать при разработке BLE для iOS.Первый связан с симулятором iOS.Интересно, что в свое время iOS Simulator действительно поддерживал разработку Bluetooth (видео Bluetooth 101 WWDC 2012 ссылается на эту функцию), но на WWDC 2013 Apple объявила, что поддержка Bluetooth больше не будет в Simulator.На первый взгляд это кажется неудачным.Тем не менее, разработка на устройстве - лучший и более точный опыт работы с BLE.Кроме того, поскольку все iPhone, выпущенные после iPhone 4s (2011), имеют Bluetooth 4.0 - и, соответственно, BLE - большинство разработчиков iOS уже имеют устройства, которые поддерживают его.Нам почти даже не нужно задавать вопрос, но хорошо знать, кто может его использовать, если у вас есть ограниченный набор типов устройств, для которых вы разрабатываете приложения или устройства BLE.

Еще одно важное требование, которое следует помнить при разработке Core Bluetooth, заключается в том, что Apple возлагает основную ответственность за взаимодействие с устройствами BLE на разработчика приложений.Очень мало управляется и поддерживается самой iOS в отношении управления Bluetooth.Одной вещью, которой управляют в ОС, является соединение, которое появляется в Настройках> Приложение Bluetooth.

0 голосов
/ 26 сентября 2011

Вот практическая разница для вашей первой точки:

Если я передам скаляр в блок, используемый в очереди GCD, то внутри блока я работаю с копией исходных данных. Изменения не будут видны за пределами блока. (Есть предостережения по этому поводу, например, модификатор __block, но в целом это правильно.)

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

В любом случае управление памятью выполняется для вас, то есть либо копируется скалярная переменная, либо сохраняются объекты.

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

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

...