2014-12-23 2 views
1

Я пытаюсь написать функцию в ObjectC, которая возвращает класс с 3 свойствами. Для каждого свойства программа должна извлекаться с удаленного сервера (AFNetworking now), мне интересно, какое хорошее решение для этой проблемы? Вот текущая структура функции Я пишуИспользование AFNetworking для извлечения данных из нескольких ресурсов и возврата

- (MyClass *)fillInClassAndReturn { 
    MyClass *myClass = [MyClass new]; 
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 
    [manager GET:@"Url1" 
     parameters:parameter1 
     success:^(AFHTTPRequestOperation *operation, id responseObject) { 
      myClass.property1 = responseObject; 
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
      myClass.property1 = nil; 
     }]; 
    [manager GET:@"Url2" 
     parameters:parameter2 
     success:^(AFHTTPRequestOperation *operation, id responseObject) { 
      myClass.property2 = responseObject; 
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
      myClass.property2 = nil; 
     }]; 
    [manager GET:@"Url13" 
     parameters:parameter3 
     success:^(AFHTTPRequestOperation *operation, id responseObject) { 
      myClass.property3 = responseObject; 
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
      myClass.property3 = nil; 
     }]; 
    return myClass; 
} 

Эта функция возвращает myClass сразу после того, как эта функция вызывается, все три свойства будут nil в это время и когда соответствующие данные извлекаются из сервера, он будет заполнен. Таким образом, люди, которые используют эту функцию, должны будут определить KVO для возвращаемого значения функции и получать уведомление при изменении значения. Но вот проблемы с этим дизайном, он не будет работать, если возвращаемое значение NSArray/NSMutableArray вместо MyClass Итак, есть ли лучший дизайн, чтобы я мог позаботиться об этой ситуации? Если этот дизайн не так ужасен, как обрабатывать корпус NSArray*?

ответ

3

Несколько наблюдений:

  1. Поскольку это метод, который работает в асинхронном режиме, вы не хотите, чтобы попытаться вернуть что-либо сразу, а использовать шаблон завершения блок, completionHandler который будет называться когда три запроса выполнены.

  2. Поскольку у вас есть три запроса, которые запускаются одновременно, вам нужен какой-то способ узнать, когда все три сделаны. Поскольку вы используете решение на основе NSOperation (AFHTTPRequestOperation), вы можете использовать зависимости от операций.

Во всяком случае, это дает что-то вроде:

- (void)fillInClassWithCompletion:(void (^)(MyClass *myClass))completionHandler { 
    MyClass *myClass = [MyClass new]; 

    NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{ 
     if (completionHandler) { 
      completionHandler(myClass); 
     } 
    }]; 

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 

    NSOperation *operation1 = [manager GET:@"Url1" parameters:parameter1 success:^(AFHTTPRequestOperation *operation, id responseObject) { 
     myClass.property1 = responseObject; 
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
     myClass.property1 = nil; 
    }]; 
    [completionOperation addDependency:operation1]; 

    NSOperation *operation2 = [manager GET:@"Url2" parameters:parameter2 success:^(AFHTTPRequestOperation *operation, id responseObject) { 
     myClass.property2 = responseObject; 
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
     myClass.property2 = nil; 
    }]; 
    [completionOperation addDependency:operation2]; 

    NSOperation *operation3 = [manager GET:@"Url13" parameters:parameter3 success:^(AFHTTPRequestOperation *operation, id responseObject) { 
     myClass.property3 = responseObject; 
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
     myClass.property3 = nil; 
    }]; 
    [completionOperation addDependency:operation3]; 

    [[NSOperationQueue mainQueue] addOperation:completionOperation]; 
} 

Это, вероятно, самый логичный подход. Технически, если вы изменили completionQueue в AFHTTPRequestOperationManager быть параллельной очереди, выше вводит возможные условия гонки, поэтому в качестве альтернативы может использовать механизм отправки группы, чтобы знать, если все три были сделаны:

- (void)fillInClassWithCompletion:(void (^)(MyClass *myClass))completionHandler { 
    MyClass *myClass = [MyClass new]; 

    dispatch_group_t group = dispatch_group_create(); 

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 

    dispatch_group_enter(group); 
    [manager GET:@"Url1" parameters:parameter1 success:^(AFHTTPRequestOperation *operation, id responseObject) { 
     myClass.property1 = responseObject; 
     dispatch_group_leave(group); 
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
     myClass.property1 = nil; 
     dispatch_group_leave(group); 
    }]; 

    dispatch_group_enter(group); 
    [manager GET:@"Url2" parameters:parameter2 success:^(AFHTTPRequestOperation *operation, id responseObject) { 
     myClass.property2 = responseObject; 
     dispatch_group_leave(group); 
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
     myClass.property2 = nil; 
     dispatch_group_leave(group); 
    }]; 

    dispatch_group_enter(group); 
    [manager GET:@"Url13" parameters:parameter3 success:^(AFHTTPRequestOperation *operation, id responseObject) { 
     myClass.property3 = responseObject; 
     dispatch_group_leave(group); 
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
     myClass.property3 = nil; 
     dispatch_group_leave(group); 
    }]; 

    dispatch_group_notify(group, manager.completionQueue ?: dispatch_get_main_queue(), ^{ 
     if (completionHandler) { 
      completionHandler(myClass); 
     } 
    }); 
} 

В любом случае, как вы бы использовать это было бы:

[object fillInClassWithCompletion:^(MyClass *myClass) { 
    // use myClass here 
}]; 

вы можете расширить этот completionHandler передать обратно объект ошибки, тоже, как это обычная практика, и может быть полезно, если вызывающий абонент хочет, чтобы настроить обработку его ошибка в основе характера ошибки, но я оставлю это вам.

Смежные вопросы