0

我正在使用一个NSProxy子类并forwardInvocation:用于捕获对我的后端 API 对象(共享实例)的调用。

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

方法参数 (of 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我在调用后直接读取的类型(我用来显示活动指示器)。但是代理不会立即转发呼叫,因此返回值不存在 - 当然(我是盲目的)。什么是可能的解决方法?我可以返回占位符值吗?或者当方法被调用时我如何知道调用者,以便稍后检索返回值?

4

1 回答 1

0

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

if (authenticationRefreshNeeded) {

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

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

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

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

于 2014-04-21T19:33:35.050 回答