情况如下:
>我禁用WiFi并运行应用程序.
>即使没有可达性,我也通过从MKNetworkEngine子类创建MKNetworkOperation来请求(使用POST)一些数据.在请求数据之前,操作被设置为freezable(根据Mugunth Kumar’s doc).
>启用WiFi后,调用MKNetworkEngine中的checkAndRestoreFrozenOperations,它会检测到有一个挂起的操作(创建一个没有可达性的操作),它会尝试入队.
>之后,我的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;
解决方法
> resume:Freeze / Unfreeze机制仅在启用缓存时有效
您必须在AppDelegate -didFinishLaunchingWithOptions中调用-useCache:
self.networkEngine = [[MKNetworkEngine alloc] init ...]; [self.networkEngine useCache]; // <- Add this line
>完成:网络状态更改时(即解冻后)不会调用完成回调
然而,如果您采取行动(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,以便可以从主线程收听所述通知并更改UI;请参阅NSOperation and NSNotificationCenter on the main thread):
-(void) operationSucceeded { NSDictionary * aUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: self,NSStringFromClass([MKNetworkOperation class]),nil]; NSNotification * notification = [NSNotification notificationWithName:MKNetworkOperationCompletionNotification object:nil userInfo:aUserInfo]; [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:notification]; ...
3C.在MKNetworkOperation.m -operationFailedWithError中广播失败通知
-(void) operationFailedWithError:(NSError*) error { self.error = error; NSDictionary * aUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: self,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];
3E.监听器的示例代码:
- (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]); }
这样做,你已经完成了. X.
(编辑在上一个答案中删除了对MKNetworkOperation.h不必要的建议更改,并添加了第3段以显示如何克服^ {}限制.)