NSProxy和forwardInvocation:在块内调用的调用导致nil返回值

时间:2014-04-21 18:19:48

标签: ios block retain nsinvocation nsproxy

我正在使用NSProxy子类和forwardInvocation:来捕获对我的Backend API对象(共享实例)的调用。

一些背景资料: 我想捕获API调用,以便每次都可以检查是否必须刷新我的身份验证令牌。如果是,我只是在之前执行刷新。

方法参数(invocation)包含块。

一些简化的代码:

- (void)forwardInvocation:(NSInvocation *)invocation {

    [invocation setTarget:self.realAPI];
    [invocation retainArguments];

    // Perform refresh call and forward invocation after
    // successfully refreshed
    if (authenticationRefreshNeeded) {

        [self.realAPI refreshWithBlock:^(NSObject *someObject) {

            [invocation invokeWithTarget:self.realAPI];

        }];
    }
    // Otherwise we just forward the invocation immediately 
    else {

        [invocation invokeWithTarget:self.realAPI];
    }

    return;
}

我已经在调用retainArguments所以我的块和其他参数不会因为invokeWithTarget:的执行迟到而丢失(refreshWithBlock:进行异步API调用)。

到目前为止一切正常 - 但是:

在刷新块中执行nil时,调用的返回值始终为invokeWithTarget:。有没有办法保留返回值(如参数)?

任何提示?建议?


更新

作为对@quellish的回应: 问题是返回值是NSURLSessionDataTask类型(用于显示活动指示符),我在调用后直接读取。但代理不会立即转发呼叫,因此返回值不存在 - 当然(我是盲人)。 什么是可能的解决方法?我可以返回占位符值,或者在调用方法时如何知道调用者,以便稍后检索返回值?

1 个答案:

答案 0 :(得分:0)

要在调用完成时执行操作,请传递结果:

if (authenticationRefreshNeeded) {

    [self.realAPI refreshWithBlock:^(NSObject *someObject) {
        NSURLSessionDataTask    *resultTask = nil;
        [invocation invokeWithTarget:self.realAPI];
        [invocation getReturnValue:&resultTask];
        if (completion != nil){
            completion(resultTask);
        }
    }];
}

其中completion()是一个以NSURLSessionDataTask为参数的块。块可以用作回调,这使得它们非常适合你想要做的事情(“当我完成时,做这个()”)理想情况下,这将被传递到包含上述的方法 - 但是因为这个是forwardInvocation:,这会更具挑战性。您可以将其设置为此代理对象的属性并从那里读取它。

另一种方法是使用类别或非正式协议扩展UIApplication,使用addDataTask:之类的方法,您可以调用而不是块,这样可以将“我刚刚添加数据任务”的响应权移交给另一个接收者,很可能是应用程序的委托(并且您可以使用新方法application:didAddDataTask:扩展UIApplicationDelegate协议来处理此问题)。听起来您的数据任务和活动指标是应用程序级别的问题,这可能使其非常适合。

那就是说,我有一些经验几乎完全你想要解决的问题(基于令牌的授权)。我建议看一下ACAccountStore如何解决这个问题,它可能会为替代实现提供一些想法。