从异步SQL方法返回值

时间:2016-01-12 09:20:21

标签: objective-c

我有这段代码:

- (NSString *)obtenerDatosUsuario
{
   __block NSString *result=@"";
    [self obtenerDatosUsuarioSQL:^(NSString *resultadoSQL){
        result=resultadoSQL;
    }];
    return result;
} 

我希望返回的内容为resultadoSQL

2 个答案:

答案 0 :(得分:0)

如果我对你的方法-obtenerDatosUsuarioSQL:内发生的事情的猜测是正确的(即,它在后台线程中执行冗长的操作,并将结果提供给传递的块参数),那么你的代码将在下面运行顺序:

  1. 您致电-obtenerDatosUsuario
  2. 您致电-obtenerDatosUsuarioSQL:,传递完成处理程序阻止。
  3. 执行前进并到达return末尾的-obtenerDatosUsuario语句,然后退出方法正文。 返回的变量result尚未设置!
  4. 稍后,SQL查询完成并执行块。但是返回结果为时已晚,因为执行已经退出方法-obtenerDatosUsuario

答案 1 :(得分:0)

有一些方法可以使这个异步方法同步运行(例如信号量),但它通常是一个非常非常糟糕的主意。最有可能的是,obtenerDatosUsuarioSQL是异步的,因为有可能(即使只有很小的机会)结果不会立即返回。也许SQL可能会很慢。或者,您最终可能会从多个线程进行查询,因此此查询可能必须等待其他线程中的查询完成。或者可能还有其他原因。但无论什么原因,这种方法都是作为异步方法实现的,你应该接受它,而不是反对它。如果您将obtenerDatosUsuario更改为同步返回,则可以解决各种可能的问题。

相反,您应该在代码中采用异步模式。例如,让我们假设您有一些代码计划将obtenerDatosUsuario的结果用于其他目的,例如:

NSString *resultadoSQL = [self obtenerDatosUsuario];
// use `resultadoSQL` here

只需将其更改为:

[self obtenerDatosUsuarioSQL:^(NSString *resultadoSQL){
    // use `resultadoSQL` here
}];
// but not here

而且,如果您在某种方法中使用obtenerDatosUsuarioSQL,而您当前正试图立即返回该值,那么也要将其更改为异步行为。例如,让我们假设你有类似的东西:

- (NSString *)someOtherMethod {
    NSString *resultadoSQL = [self obtenerDatosUsuario];

    // let's assume you're doing something else with `resultadoSQL` to build some other string

    NSString *string = ...  // some expression using `resultadoSQL`
    return string;
}

然后,您将其更改为也采用异步模式:

- (void)someOtherMethod:(void (^)(NSString *))completionHandler {
    [self obtenerDatosUsuarioSQL:^(NSString *resultadoSQL){
        NSString *string = ...  // some expression using `resultadoSQL`
        completionHandler(resultadoSQL);
    }];
}

当你第一次遇到这个时,这看起来似乎不必要地复杂,但异步编程是如此关键,这是Cocoa编程的一个基本部分,人们必须熟悉这些常见的异步模式,比如块。就个人而言,我们在Xcode" Code Snippet Library"中使用了块语法,以至于我create code snippets。 for typical block patterns,它简化了生活,让你走出了记忆不直观的块语法的世界。

但是不要试图将异步方法包装在另一个使其同步运行的方法中。如果你这样做,你可以解决许多类型的问题。