【问题标题】:MKNetworkKit operation doesn't resume/complete when reachability changes可访问性更改时,MKNetworkKit 操作不会恢复/完成
【发布时间】:2012-10-30 13:24:41
【问题描述】:

我是 MKNetworkKit 的新手,但我已经能够将其添加到我的项目中,并且除了处理可达性更改外,它运行良好。

情况如下:

  1. 我禁用 WiFi 并运行应用程序。
  2. 即使没有可达性,我通过从我的MKNetworkEngine 子类创建一个MKNetworkOperation 来请求(使用POST)一些数据。在请求数据之前,该操作被设置为可冻结(根据Mugunth Kumar's doc)。
  3. 启用 WiFi 后,MKNetworkEngine 中的 checkAndRestoreFrozenOperations 被调用,它检测到有一个挂起的操作(创建时没有可达性),它试图入队。
  4. 在那之后,我的onCompletion 块永远不会被调用。

对于MKNetworkKit 中的冻结操作+可达性,我有什么不明白的地方吗?冻结是否仅适用于请求开始后可达性发生变化的操作?或者我应该实现我自己的 reachability changed 块?

这是我的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;

【问题讨论】:

  • 你在引擎中设置了主机吗?如果您查看如何处理冻结操作,除非为引擎定义了主机,否则它们将不起作用。
  • @KenWoo 是的。我的引擎子类中的 init 方法调用[super initWithHostName:<HOSTNAME>]
  • @msoler 你让它工作了吗?我也有类似的问题
  • @alandalusi 不,对不起。我一直忙于项目的几个部分,几乎忘记了这一点。我试图联系 MKNetworkKit 的开发者,但没有得到回应。
  • 如果你通过 checkAndRestoreFrozenOperations 函数,它会创建新的 MKOperation,所以你的块不会被调用。但问题是在这种情况下,post 数据没有上传到服务器。

标签: ios network-programming mknetworkkit mknetworkengine


【解决方案1】:

这是两个独立的问题:恢复与完成。

  1. resume:冻结/解冻机制仅在缓存启用时起作用

    您必须在 AppDelegate -didFinishLaunchingWithOptions 中调用 -useCache:

    self.networkEngine = [[MKNetworkEngine alloc] init ...];
    [self.networkEngine useCache]; // <- Add this line
    
  2. 完成:完成回调在网络状态改变时调用(即在解冻之后)

    但是,如果您采取措施 (1.) 并在 MKNetworkOperation.m -checkAndRestoreFrozenOperations 中的以下行放置一个断点:

    [self enqueueOperation:pendingOperation]
    

    您会发现它在网络连接恢复时被调用,而 pendingOperation 是您的待处理 POST。但是,由于新的 MKNetworkOperation 已被实例化(到那时完成块可能不再存在),您的 onCompletion 块永远不会被调用。一种可能的解决方法是使用通知而不是回调。

  3. 完全修复: 比 (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,   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];
    

    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]);
    }
    

这样做,你就完成了。十。

已编辑以删除先前答案中对 MKNetworkOperation.h 的不必要的建议更改,并添加了第 3 段。以展示如何克服 ^{} 限制。

【讨论】:

  • 非常感谢您的详细回答,@gothicdev。
猜你喜欢
  • 1970-01-01
  • 2013-07-01
  • 2016-06-24
  • 2016-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-28
  • 1970-01-01
相关资源
最近更新 更多