【问题标题】:return method is failing in a completion block [duplicate]返回方法在完成块中失败[重复]
【发布时间】:2014-02-13 02:50:51
【问题描述】:

我有这个问题,为什么我不能RETURN在值:

- (NSArray *)SQLRetrieve:(NSString *)barID {

    self.client = [MSClient clientWithApplicationURLString:@"https://outnight-mobile.azure-mobile.net/" applicationKey:@"okYeRGfBagYrsbkaqWIRObeDtktjkF10"];
    [self.client invokeAPI:@"photos"
                      body:barID
                HTTPMethod:@"POST"
                parameters:nil
                   headers:nil
                completion:^(id result, NSHTTPURLResponse *response, NSError *error) {
                    if (error) {
                        NSLog(@"Error %@", error );
                    } else
                    {
                        NSString *string = [NSString stringWithFormat:@"%@", [result objectForKey:@"rows"]];
                        NSString *stringWithoutbracketsend = [string stringByReplacingOccurrencesOfString:@")" withString:@""];
                        NSString *stringWithoutbracketsfront = [stringWithoutbracketsend stringByReplacingOccurrencesOfString:@"(" withString:@""];
                        NSString *completion = [stringWithoutbracketsfront stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
                        NSString *newStr = [completion substringFromIndex:1];
                        NSString *finalstring = [newStr substringToIndex:newStr.length-(newStr.length>0)];
                        //NSLog(@"%@", finalstring);
                        [MyArray addObject:finalstring];
                        NSLog(@"%@", [MyArray objectAtIndex:0]);
                        return finalstring;
                    }
                }];

之后出现错误。 我附上了错误的图片。完全迷失了——谁能告诉我们问题出在哪里,给我们留下深刻印象

【问题讨论】:

  • It errors like crazy. 这些错误可能是什么?
  • 不兼容的块指针类型发送 NSString 响应强。
  • 为什么要返回字符串,而它需要是一个数组?
  • 嗯?我以为第一个是返回类型,即 NSArray ?
  • 完成块被异步调用。您不能从块内的 SQLRetrieve 方法返回。

标签: ios objective-c nsstring


【解决方案1】:

您正试图从完成块内部返回一个值,但该块具有void 返回类型。这就是编译器抱怨的原因。

如果您希望此方法从该(可能)异步执行的完成块中返回值,则不应尝试从该块中返回值,而应自己使用异步完成块模式:

- (void)SQLRetrieve:(NSString *)barID completion:(void (^)(NSString *string, NSError *error))completion {

    self.client = [MSClient clientWithApplicationURLString:@"https://outnight-mobile.azure-mobile.net/" applicationKey:@"..."];
    [self.client invokeAPI:@"photos"
                      body:barID
                HTTPMethod:@"POST"
                parameters:nil
                   headers:nil
                completion:^(id result, NSHTTPURLResponse *response, NSError *error) {
                    if (error) {
                        if (completion)
                            completion(nil, error);

                        // or, you might want to explicitly dispatch that completion block back to the main queue:
                        //
                        // if (completion)
                        //     dispatch_async(dispatch_get_main_queue(), ^{
                        //         completion(nil, error);
                        //     });
                    } else {
                        NSString *string = [NSString stringWithFormat:@"%@", [result objectForKey:@"rows"]];
                        NSString *stringWithoutbracketsend = [string stringByReplacingOccurrencesOfString:@")" withString:@""];
                        NSString *stringWithoutbracketsfront = [stringWithoutbracketsend stringByReplacingOccurrencesOfString:@"(" withString:@""];
                        NSString *completion = [stringWithoutbracketsfront stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
                        NSString *newStr = [completion substringFromIndex:1];
                        NSString *finalstring = [newStr substringToIndex:newStr.length-(newStr.length>0)];

                        if (completion)
                            completion(finalstring, nil);

                        // or, you might want to explicitly dispatch that completion block back to the main queue:
                        //
                        // if (completion)
                        //     dispatch_async(dispatch_get_main_queue(), ^{
                        //         completion(finalstring, nil);
                        //     });
                    }
                }];
}

然后你会像这样调用它:

[self SQLRetrieve:@"your-bar-id" completion:^(NSString *string, NSError *error) {
    if (error) {
        // do whatever you want upon error
        NSLog(@"Error %@", error );
    } else {
        // do whatever you want with the string, for example
        [MyArray addObject:string];
    }
}];

我不知道如何调和这样一个事实,即您声明了一个声称返回数组的方法,但您似乎返回了一个字符串,所以我只是假设您确实打算使用后者(正如您从我的代码示例中看到的那样)。如果您真的想返回数组,那么只需更改完成块以传回数组,然后更改代码以实际传回该数组。

这里的一个相关但更微妙的问题是,您的原始代码示例似乎正在返回一个字符串,但还将该字符串添加到MyArray,您在此代码示例的其他地方没有引用它。对于从异步调用的代码块中更新模型对象,您应该非常谨慎。 (因为当此代码异步运行时,您可能有一个继续引用 MyArray 的 UI,如果您在中途更改它可能会感到困惑。)将块传递给 @987654326 可能更安全@更新MyArray,就像我上面所说的那样。如果invokeAPI 的完成块不能保证在主队列上运行,您可能希望将自己的完成块显式分派回主队列。您要确保不仅更新主队列上的 UI,而且您可能还想确保只更新主队列中的模型对象(这是避免同步错误的最简单方法)。

【讨论】:

    【解决方案2】:

    预期块类型的返回类型是 void,而不是您通过添加返回指定的 NSString。不能返回值。

    【讨论】:

      【解决方案3】:

      首先,您会将退货存放在哪里?通常将返回值分配给调用中的变量:

      NSString *string = [NSString alloc] init];
      

      [[NSString alloc] init] 的返回值赋值给*string。在你的情况下:

      [self.client invokeAPI ...
      

      没有变量可以分配给回报,所以你的回报是没有意义的。

      现在出现错误:它表示您正在尝试将返回类型为 NSString* 的函数发送到返回类型为 void (MSAPIBlock aka (void(^)) 的函数。异步块不能将变量返回给您的代码,因为它们可以在您的代码完成之后完成。在您的情况下,我认为您需要分派到一个单独的函数来处理您的finalString。在完成块的末尾添加:

      dispatch_async( dispatch_get_main_queue(), ^{
          [self doSomethingWithReturnString:finalString];
      });
      

      编辑:为您的函数添加完整代码

      - (NSArray *)SQLRetrieve:(NSString *)barID {
      
          self.client = [MSClient clientWithApplicationURLString:@"https://outnight-mobile.azure-mobile.net/" applicationKey:@"okYeRGfBagYrsbkaqWIRObeDtktjkF10"];
          [self.client invokeAPI:@"photos"
                            body:barID
                      HTTPMethod:@"POST"
                      parameters:nil
                         headers:nil
                      completion:^(id result, NSHTTPURLResponse *response, NSError *error) {
                          if (error) {
                              NSLog(@"Error %@", error );
                          } else
                          {
                              NSString *string = [NSString stringWithFormat:@"%@", [result objectForKey:@"rows"]];
                              NSString *stringWithoutbracketsend = [string stringByReplacingOccurrencesOfString:@")" withString:@""];
                              NSString *stringWithoutbracketsfront = [stringWithoutbracketsend stringByReplacingOccurrencesOfString:@"(" withString:@""];
                              NSString *completion = [stringWithoutbracketsfront stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
                              NSString *newStr = [completion substringFromIndex:1];
                              NSString *finalstring = [newStr substringToIndex:newStr.length-(newStr.length>0)];
                              //NSLog(@"%@", finalstring);
                              [MyArray addObject:finalstring];
                              NSLog(@"%@", [MyArray objectAtIndex:0]);
      
                              dispatch_async( dispatch_get_main_queue(), ^{
                                  [self doSomethingWithReturnString:finalString];
                              });
                          }
                      }];
      }
      
      -(void)doSomethingWithReturnString:(NSString*)string
      {
          //Do whatever you need to with the return string here, 
          //if you don't need it anymore then no need to call this function 
          //(you already added it to your array)
      }
      

      【讨论】:

      • 听起来很公平,因为我完全被卡住了,请你再帮忙一点
      • 我给了你代码,请告诉我你对什么感到困惑,我会尽力而为。
      • 好的,所以我需要将最终字符串放入另一个方法并将它们存储在那里。
      • 所以首先我将方法分配为 VOID 并且不返回任何变量,然后使用 alloc init 分配变量。然后把dispatch_async放在block的最底部,然后获取另一个存储这些变量的方法?
      • 你不需要将方法分配给任何东西,只是不要调用return。然后,您可以根据需要分派和使用该字符串。如果你想要的只是添加到数组中的字符串,那么你不需要调度,继续你的生活。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-10
      • 1970-01-01
      • 2020-04-15
      • 2017-05-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多