我正在使用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
类型(用于显示活动指示符),我在调用后直接读取。但代理不会立即转发呼叫,因此返回值不存在 - 当然(我是盲人)。
什么是可能的解决方法?我可以返回占位符值,或者在调用方法时如何知道调用者,以便稍后检索返回值?
答案 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如何解决这个问题,它可能会为替代实现提供一些想法。