如何从iOS块内部返回方法对象

时间:2015-05-15 13:36:55

标签: ios objective-c nsarray return-value objective-c-blocks

返回类型的方法是NSArray,所以当我调用这个方法时,我得到nil或空数组。这是它在我的方法实现之下:

- (NSArray *)startParsing {
    __block NSArray *array;
    allProductsID = [[NSMutableArray alloc] init];
    NSString *string = [NSString stringWithFormat:@"http://%@:@%@",kPrestaShopAPIKey, kPrestaShopURLString];
    NSURL *url = [NSURL URLWithString:string];

    AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:url];
    manager.responseSerializer = [AFXMLParserResponseSerializer serializer];

    [manager GET:@"categories/21" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSXMLParser *parser = (NSXMLParser *)responseObject;
        [parser setShouldProcessNamespaces:YES];
        parser.delegate = self;
        [parser parse];
        //NSLog(@"First response %@", responseObject);
        for (int i = 0; i< [[self.xmlShop objectForKey:@"product"] count]; i++) {
            //NSLog(@"Second ID --> %@", [self.xmlShop objectForKey:@"product"][i]);
            NSString *productID = [NSString stringWithFormat:@"products/%@", [[self.xmlShop objectForKey:@"product"][i] objectForKey:@"id"]];
            [allProductsID addObject:productID];
        }
        array = [allProductsID copy];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Error occured %@", [error localizedDescription]);
    }];
    return array;
}

任何人都可以帮我解决这个问题吗?

3 个答案:

答案 0 :(得分:7)

正如Quentin已经提到的那样,你不能直接这样做,因为你在内部执行异步请求。这意味着您的程序启动请求,然后继续其下一个语句,并且不等待请求完成。你应该做的是

  • 使请求同步,使程序等待请求完成。但是要注意不要从主线程调用此方法,因为这会阻止您的应用继续响应,直到请求返回。
  • 使用块作为startParsing方法的回调(与实际请求回调使用块的方式相同)

这样可以举例如下:

- (void)startParsing:(void (^)(NSArray*))parsingFinished {
    allProductsID = [[NSMutableArray alloc] init];
    NSString *string = [NSString stringWithFormat:@"http://%@:@%@",kPrestaShopAPIKey, kPrestaShopURLString];
    NSURL *url = [NSURL URLWithString:string];

    AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:url];
    manager.responseSerializer = [AFXMLParserResponseSerializer serializer];

    [manager GET:@"categories/21" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        // do your parsing...
        parsingFinished([allProductsID copy]);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        parsingFinished([[NSArray alloc] init]); 
        // or return nil or provide a parsingFailed callback
    }];
}

然后你会像

一样调用
[yourObject startParsing:^(NSArray *parsedData) {
    // do something with the parsed data
}];

答案 1 :(得分:2)

你不能。
在您的情况下,块是异步执行的。这意味着在执行块时,您的方法可能已经返回。

您需要调用另一个方法或从块中发送NSNotification以传递数组。

答案 2 :(得分:0)

应该返回枚举值的方法

- (RXCM_TroubleTypes) logic_getEnumValueOfCurrentCacheProblem
{
    RXCM_TroubleTypes result = RXCM_HaveNotTrouble;
    NetworkStatus statusConnection = [self network_typeOfInternetConnection];

    RXCM_TypesOfInternetConnection convertedNetStatus = [RXCM convertNetworkStatusTo_TypeOfInternetConnection:statusConnection];


    BOOL isAllowed = [self someMethodWith:convertedNetStatus];
    if (isAllowed){
        return RXCM_HaveNotTrouble;
    }else { 
        return RXCM_Trouble_NotSuitableTypeOfInternetConnection;
    }

   return result;
}

使用block调用委托人方法的方法。 并等待答案。 在这里我使用while循环。只需检查每隔0.5秒的答案

- (BOOL) isUserPermissioned:(RXCM_TypesOfInternetConnection)newType
{
    __block BOOL isReceivedValueFromBlock = NO;
    __block BOOL result = NO;
    __block BOOL isCalledDelegateMethod = NO;

    dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
    dispatch_sync(aQueue,^{

        while (!isReceivedValueFromBlock) {
            NSLog(@"While");
            if (!isCalledDelegateMethod){
                [self.delegate rxcm_isAllowToContinueDownloadingOnNewTypeOfInternetConnection:newType
                                                                                   completion:^(BOOL isContinueWorkOnNewTypeOfConnection) {
                                                                                       result = isContinueWorkOnNewTypeOfConnection;
                                                                                       isReceivedValueFromBlock = YES;
                                                                                   }];
                isCalledDelegateMethod = YES;
            }
            [NSThread sleepForTimeInterval:0.5];

        }
    });
    return result;
}

ViewController中的委托方法

- (void) rxcm_isAllowToContinueDownloadingOnNewTypeOfInternetConnection:(RXCM_TypesOfInternetConnection)newType
                                                             completion:(void(^)(BOOL isContinueWorkOnNewTypeOfConnection))completion
{
    __weak ViewController* weak = self;

    dispatch_async(dispatch_get_main_queue(), ^{
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Alert"
                                                                       message:@"to continue download on the new type of connection"
                                                                preferredStyle:UIAlertControllerStyleAlert];

        UIAlertAction *ok = [UIAlertAction actionWithTitle:@"YES" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completion(YES);
        }];

        UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"NO" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            completion(NO);
        }];

        [alert addAction:cancel];
        [alert addAction:ok];
        [weak presentViewController:alert animated:YES completion:nil];

    });
}