Лучшая практика для отправки большого количества данных в фоновом режиме на устройстве iOS4?

У меня есть приложение, которому необходимо отправлять данные (используя POST) на сервер. Эта функция должна быть на одном из субконтроллеров NavigationController, и пользователь должен иметь возможность уйти от этого контроллера и/или закрыть приложение (будет поддерживаться только iPhone4/iOS4). Должен ли я использовать потоки/NSOperations или/и отправлять данные с использованием существующих асинхронных методов? Любые идеи/лучшие практики, как это реализовать?


person cocoapriest    schedule 13.10.2010    source источник


Ответы (5)


Хорошо, я отвечу на свой вопрос. Во-первых, как сказал tc, лучше иметь этот вызов для делегата приложения, чтобы представление в NavigationController можно было закрыть. Во-вторых, отметьте начало фоновой обработки beginBackgroundTaskWithExpirationHandler: и завершите ее endBackgroundTask: следующим образом:

.h:

UIBackgroundTaskIdentifier bgTask;

.m:

- (void)sendPhoto:(UIImage *)image
{
  UIApplication *app = [UIApplication sharedApplication];

  bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
    [app endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid;
  }];


  NSLog(@"Sending picture...");

  // Init async NSURLConnection

  // ....
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

  NSLog(@"Picture sent.");
  
  UIApplication *app = [UIApplication sharedApplication];

  if (bgTask != UIBackgroundTaskInvalid) {
    [app endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid;
  }
}

У вас есть 10 минут, прежде чем iOS закроет ваше приложение. Вы можете проверить это время с помощью [app backgroundTimeRemaining]

person cocoapriest    schedule 15.10.2010
comment
ну, я вижу 10-минутное ограничение по времени во многих сообщениях, но есть упоминания о том, что вы можете еще больше увеличить срок, вызвав beginBackgroundTaskWithExpirationHandler: снова. /iphone-app-running-http-requests-while-application-in-background/3587547#3587547" title="Приложение для iPhone, выполняющее HTTP-запросы в фоновом режиме"> stackoverflow.com/questions/3291840/ - person palaniraja; 30.05.2011
comment
@CocoaPriest ты преодолел 10-минутный лимит времени? - person owen gerig; 04.01.2012
comment
вам нужно что-то делать в applicationDidEnterBackground? - person dips; 03.08.2012
comment
Я получаю ошибки, когда объявляю UIBackgroundTaskIdentifier bgTask; в моем заголовке, должно ли это быть вне вызова @interface? XCode не жалуется, когда я публикую его ниже @end, но он все равно не работает - person Kyle C; 18.09.2012
comment
Что произойдет, если я не вызову метод endBackgroundTask. - person quang thang; 01.06.2016

Я бы просто использовал NSURLConnection. Это немного сложно, если вы хотите отправить multipart/form-data (см. пример SimpleURLConnections/PostController.m). Я бы вставил его в делегат приложения, но я такой ленивый.

Вы вообще не должны беспокоиться о потоках, если только неблокирующий ввод-вывод (т.е. NSURLConnection) не слишком медленный. Многопоточность имеет свои накладные расходы, взаимодействие между потоками — это боль, а взаимоблокировки ужасны.

Что вам нужно сделать, так это запустить фоновую задачу, чтобы ваше приложение могло продолжать выполняться в фоновом режиме (завершите фоновую задачу в connectionDidFinishLoading: и connection:didFailWithError). Фоновым приложениям дается около 10 минут для завершения выполнения фоновых задач.

person tc.    schedule 14.10.2010
comment
хорошо, и вот вопрос: как мне разрешить уже запущенному потоку (здесь: NSURLConnection) продолжать выполнение в фоновом режиме после закрытия приложения? - person cocoapriest; 14.10.2010

Используйте ASIHTTP и настройте очередь. Всю необходимую информацию можно найти здесь:

http://allseeing-i.com/ASIHTTPRequest/

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

Он используется множеством замечательных приложений для iPhone.

person Jordan    schedule 14.10.2010
comment
Потому что хороший сетевой код не требует отдельного потока. Что вы имеете в виду настроить асинхронную очередь? NSOperationQueue? Это совершенно не нужно. - person tc.; 14.10.2010
comment
Я имел в виду, что пост должен работать в фоновом режиме, чтобы не загружать пользовательский интерфейс. - person Jordan; 14.10.2010
comment
И как я могу сохранить эту очередь для выполнения в фоновом режиме (после закрытия приложения)? - person cocoapriest; 14.10.2010
comment
Apple не разрешает фоновую обработку, такую ​​как то, что вы хотите сделать, для приложений, которые не находятся на переднем плане. Пожалуйста, взгляните на ответ ASIHTTPRequest, который я предоставил выше. Это все, что вам нужно. - person Jordan; 14.10.2010
comment
На iOS4 это разрешено около 10 минут, как уже сказал tc - person cocoapriest; 14.10.2010
comment
Вам не нужно настраивать NSOperationQueue/очередь отправки/что угодно, чтобы запускать что-то в фоновом режиме. Если есть сомнения, я бы просто использовал NSURLConnection; Я еще не нашел веских причин для использования ASIHTTPConnection. - person tc.; 21.11.2010
comment
Джордан, вы говорите о запуске соединения в «фоновом потоке», в то время как приложение все еще работает на переднем плане. Константин говорит о подключении выхода приложения в фон, что разрешено после iOS 4. - person Joseph Lin; 29.06.2011
comment
ASIHttpRequest имеет флаг с именем shouldContinueWhenAppEntersBackground. Установите значение «да», и вы получите фоновое изображение бесплатно. - person Mugunth; 08.08.2011

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

Еще одна вещь, о которой вам нужно подумать, это то, что произойдет, если пользователь запустит процесс, а затем нажмет кнопку «Домой». Как повлияет на взаимодействие с сервером прерывание? Может ли он продолжиться, когда пользователь в следующий раз войдет в приложение? и Т. Д.

person drekka    schedule 13.10.2010
comment
это именно те вопросы, которые мне нужно исследовать. Если вы отправляете данные в новом потоке, нужно ли мне использовать методы асинхронной синхронизации или синхронизации для отправки данных?.. - person cocoapriest; 14.10.2010

Я хотел бы поддержать сообщение, в котором упоминается:

bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
      [app endBackgroundTask:bgTask]; 

      bgTask = UIBackgroundTaskInvalid;
}];

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

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

http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/

person Jackie Treehorn    schedule 15.10.2010
comment
Синхронные соединения не рекомендуются. Да, вы пытаетесь решить проблему выхода из цикла выполнения очереди до того, как ваше соединение успеет завершиться (и отправить соответствующие сообщения обратного вызова делегата), но синхронные соединения — не лучший способ сделать это. - person MattyG; 30.08.2011