且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

返回方法在完成块中失败

更新时间:2023-02-23 10:45:50

您正试图从完成块内部返回一个值,但该块具有 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"正文:barIDHTTPMethod:@"POST"参数:无标题:无完成:^(id 结果,NSHTTPURLResponse *响应,NSError *错误){如果(错误){如果(完成)完成(无,错误);//或者,您可能希望将该完成块显式分派回主队列:////如果(完成)//dispatch_async(dispatch_get_main_queue(), ^{//完成(无,错误);//});} 别的 {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)];如果(完成)完成(最终字符串,零);//或者,您可能希望将该完成块显式分派回主队列:////如果(完成)//dispatch_async(dispatch_get_main_queue(), ^{//完成(最终字符串,零);//});}}];}

然后你会像这样调用它:

[self SQLRetrieve:@"your-bar-id" 补全:^(NSString *string, NSError *error) {如果(错误){//出错时做任何你想做的事NSLog(@"错误 %@", 错误 );} 别的 {//对字符串做任何你想做的事,例如[MyArray addObject:string];}}];

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

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

I am having this problem, why can I not RETURN at value :

- (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 comes up with an error after. I have attached an image of the error. just completely and utterly lost - can someone impress us by telling us what the problem is

You are attempting to return a value from inside the completion block, but that block has a void return type. That's why the compiler is complaining.

If you want this method to return values from within this (presumably) asynchronously executed completion block, you shouldn't try to return the value from within the block, but rather you should employ a asynchronous completion block pattern yourself:

- (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);
                        //     });
                    }
                }];
}

You'd then invoke it something like:

[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];
    }
}];

I don't know how to reconcile the fact that you declared a method that claims to return an array but you appear to return a string, so I simply presumed you really intended the latter (as you can see from my code sample). If you really wanted to return the array, then just change that completion block to pass back an array, and change to code to actually pass back that array.

A related, but more subtle issue here is that you appear to be that your original code sample is returning a string, but also adding the string to MyArray, which you don't reference elsewhere in this code sample. You should be very wary about updating model objects from within an asynchronously called block of code. (Because while this code is running asynchronously, you might have a UI that is continuing to reference MyArray, and it might be confused if you change it mid-stream.) It's probably safer to have the block that you pass to SQLRetrieve update MyArray, like I have above. And if invokeAPI's completion block is not guaranteed to run on the main queue, you might want to explicitly dispatch your own completion block back to the main queue. You want to make sure that you not only update the UI on the main queue, but you probably also want to make sure you update your model objects in the main queue only, too (it's the easiest way to avoid synchronization errors).