【问题标题】:NSProxy and forwardInvocation: invoke called within a block causes nil return valueNSProxy 和 forwardInvocation:在块内调用的调用导致 nil 返回值
【发布时间】:2014-04-21 18:19:47
【问题描述】:

我正在使用 NSProxy 子类和 forwardInvocation: 来捕获对我的后端 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 调用)。

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

在刷新块内执行invokeWithTarget: 时,调用的返回值始终为nil。有什么方法可以保留返回值(如参数)?

有什么提示吗?建议?


更新

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

【问题讨论】:

  • 你能用你在哪里/如何读取返回值来更新这个问题吗?当您调用 getReturnValue: 时,您的调用本身是否为零?
  • 这样做了。晚上剩下的时间用 Facepalm... 有什么提示可以解决这个问题吗?或者是否有另一种方法来拦截 API 调用以执行另一个异步任务(无需在每个 API 方法中进行刷新检查......)

标签: ios block retain nsinvocation nsproxy


【解决方案1】:

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

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 是如何解决这个问题的,它可能会为替代实现提供一些想法。

【讨论】:

  • 我不知道……这一切似乎有点难。但是非常感谢您的回答。对于我确实提出的问题,这是正确的......即使我必须继续寻找一个好的解决方案。
  • 是的,您要解决的问题-将请求作为“真实”请求(用于令牌身份验证)的先决条件是一个讨厌的问题。同样,看看requestAccessToAccountsWithType:options:completion 的工作原理,它应该会给你一些简单且相当可靠的方向。
猜你喜欢
  • 1970-01-01
  • 2016-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多