Операция MKNetworkKit не возобновляется / не завершается при изменении достижимости
Я новичок в MKNetworkKit
, но я смог добавить его в свой проект, и он отлично работает, за исключением случаев, когда речь идет об изменениях достижимости.
Вот ситуация:
- Я отключаю WiFi и запускаю приложение.
- Даже без доступности я прошу (используя
POST
) некоторые данные, создавMKNetworkOperation
от моегоMKNetworkEngine
подкласс. Непосредственно перед запросом данных операция устанавливается как блокируемая (согласно документу Мугунта Кумара). - После включения WiFi,
checkAndRestoreFrozenOperations
вMKNetworkEngine
вызывается и обнаруживает, что существует одна ожидающая операция (созданная без достижимости), которая пытается поставить в очередь. - После этого мой
onCompletion
Блок никогда не называется.
Есть ли что-то, чего я не понимаю в операциях замораживания + достижимости в MKNetworkKit
? Замораживание работает только для операций, в которых достижимость изменяется после запуска запроса? Или я должен реализовать свой собственный измененный блок достижимости?
Вот код в моем MKNetworkEngine
подкласс, который создает операцию и запускает запрос. Обратите внимание, что нерелевантный код был подавлен.
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObject:@"value" forKey:@"param"];
MKNetworkOperation *op = [self operationWithPath:MYPATH
params:params
httpMethod:@"POST"];
[op setFreezable:YES];
[op onCompletion:^(MKNetworkOperation *completedOperation) {
// ...
// Here is where I process response and send the result to my completion block
// It's called when WiFi is available, but not called otherwise.
// ...
} onError:^(NSError *error) {
// It's called when WiFi is available, but not called otherwise.
DLog(@"Some error");
}];
[self enqueueOperation:op];
return op;
1 ответ
Это две отдельные проблемы: резюме против завершения.
резюме: механизм Freeze/Unfreeze работает, только если кеш включен
Вы должны вызвать -useCache в вашем AppDelegate -didFinishLaunchingWithOptions:
self.networkEngine = [[MKNetworkEngine alloc] init ...]; [self.networkEngine useCache]; // <- Add this line
complete: обратный вызов завершения не вызывается при изменении состояния сети (т. е. после разморозки)
Тем не менее, если вы выполните действие (1.) и поместите точку останова в MKNetworkOperation.m -checkAndRestoreFrozenOperations в строке:
[self enqueueOperation:pendingOperation]
вы обнаружите, что он вызывается при восстановлении сетевого подключения, и что pendingOperation - это ожидающий POST. Однако, поскольку был создан новый MKNetworkOperation (и к тому времени блок завершения может больше не существовать), ваш
onCompletion
Блок никогда не называется. Одним из возможных путей решения этой проблемы является использование уведомления вместо обратного вызова.полное исправление: более надежный подход, чем (2), который будет работать при запуске, состоит в замене
^{}
блокировать обратные вызовы с помощью NSNotifications. Зарегистрируйте своих слушателей рано, как в вашем AppDelegate. Вот минимальные изменения, необходимые для создания уведомлений MKNetworkKit:3a. Вставить константы уведомлений в MKNetworkOperation.h
#define MKNetworkOperationCompletionNotification @"MKNetworkOperationCompletionNotification" #define MKNetworkOperationErrorNotification @"MKNetworkOperationErrorNotification"
3b. Передайте уведомление об успешном выполнении в MKNetworkOperation.m -operationSucceeded (обратите внимание, что я использую postNotificationOnMainThread, чтобы указанное уведомление можно было прослушать из основного потока и изменить пользовательский интерфейс; см. NSOperation и NSNotificationCenter в основном потоке):
-(void) operationSucceeded { NSDictionary * aUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: self, NSStringFromClass([MKNetworkOperation class]), nil]; NSNotification * notification = [NSNotification notificationWithName:MKNetworkOperationCompletionNotification object:nil userInfo:aUserInfo]; [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:notification]; ...
3в. Трансляция уведомления об ошибке в MKNetworkOperation.m -operationFailedWithError
-(void) operationFailedWithError:(NSError*) error { self.error = error; NSDictionary * aUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: self, NSStringFromClass([MKNetworkOperation class]), error, NSStringFromClass([NSError class]), nil]; NSNotification * notification = [NSNotification notificationWithName:MKNetworkOperationErrorNotification object:nil userInfo:aUserInfo]; [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:notification]; ...
3d. Зарегистрируйте довольно постоянный объект, такой как AppDelegate, в качестве прослушивателя (не забудьте отменить регистрацию):
// Listen to POST changes NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; [defaultCenter addObserver:self selector:@selector(mkNetworkOperationCompletionNotification:) name:MKNetworkOperationCompletionNotification object:nil]; [defaultCenter addObserver:self selector:@selector(mkNetworkOperationErrorNotification:) name:MKNetworkOperationErrorNotification object:nil];
3е. Пример кода того, как может выглядеть слушатель:
- (void)mkNetworkOperationCompletionNotification:(NSNotification*)notification { MKNetworkOperation *operation = [[notification userInfo] objectForKey:NSStringFromClass([MKNetworkOperation class])]; NSLog(@"operationSucceeded: %@", [operation responseString]); } - (void)mkNetworkOperationErrorNotification:(NSNotification*)notification { NSError * error = [[notification userInfo] objectForKey:NSStringFromClass([NSError class])]; NSLog(@"operationFailedWithError: %@", [error localizedDescription]); }
Сделай это, все готово. ИКС.
(Отредактировано, чтобы удалить ненужные предложенные изменения в MKNetworkOperation.h в предыдущем ответе, и добавило параграф 3., чтобы показать, как преодолеть ограничения ^{}.)