Возвращаемое значение для функции внутри блока
Я использую AFNetworking для получения данных с сервера:
-(NSArray)some function {
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success: ^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSArray *jsonArray =[JSON valueForKey:@"posts"];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {}
}
Так что я пытаюсь сделать здесь, это вернуть jsonArray в функцию. Очевидно, что возврат не работает.
Ответы
Ответ 1
Вы не можете использовать блок завершения для создания возвращаемого значения для вашего метода. AFJSONRequestOperation
выполняет свою работу асинхронно. someFunction
будет возвращаться, пока операция все еще работает. Успех и неудача Блоки - это то, как вы получаете результирующие значения, где им нужно идти.
Один из вариантов заключается в том, чтобы передать вызывающему в качестве аргумента ваш метод-оболочку, чтобы блок завершения мог передать массив.
- (void)goFetch:(id)caller
{
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success: ^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
[caller takeThisArrayAndShoveIt:[JSON valueForKey:@"posts"]];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {}
}
Вы также можете заставить своего вызывающего пользователя создать и передать блок, который будет выполняться с успехом. Затем goFetch:
больше не нужно знать, какие свойства существуют на вызывающем устройстве.
- (void)goFetch:(void(^)(NSArray *))completion
{
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success: ^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
if( completion ) completion([JSON valueForKey:@"posts"]);
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {}
}
Ответ 2
Как говорили другие, вы не можете этого сделать, когда имеете дело с асинхронным вызовом. Вместо того, чтобы возвращать ожидаемый массив, вы можете передать блок завершения в качестве параметра
typedef void (^Completion)(NSArray* array, NSError *error);
-(void)someFunctionWithBlock:(Completion)block {
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success: ^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSArray *jsonArray =[JSON valueForKey:@"posts"];
if (block) block(jsonArray, nil);
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
if (block) block(nil, error);
}
}
Тогда, когда вы называете это someFunction. Этот код также сделает правильную обработку ошибок для вас.
[yourClassInstance someFunctionWithBlock:^(NSArray* array, NSError *error) {
if (error) {
NSLog(%@"Oops error: %@",error.localizedDescription);
} else {
//do what you want with the returned array here.
}
}];
Ответ 3
i столкнулся с такой проблемой и решил ее этим методом ниже.
Я видел ответы выше, используя блоки. Но в то время это решение было более подходящим.
Логика метода проста. Вам необходимо отправить объект и его метод в качестве параметра, и после завершения запроса этот метод будет вызван.
Надеюсь, что это поможет.
+(void)request:(NSString *)link parameters:(NSDictionary *)params forInstance:(id)instance returns:(SEL)returnValue
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:link
parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
[instance performSelector:returnValue withObject: responseObject];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
[instance performSelector:returnValue withObject:nil];
//NSLog(@"Error: %@", error);
}];
}
Ответ 4
Вы можете сделать это, если напишите такую обертку. В этой ситуации вам нужен цикл while, который будет ожидать ответа от блока.
Метод, который должен возвращать значение enum
- (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;
}
Метод, который вызывает метод делегата с блоком. И ждет ответа от него. Здесь я использую цикл 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];
});
}