#iphone #objective-c #nsurlconnection #nsurlrequest
#iPhone #objective-c #nsurlconnection #nsurlrequest
Вопрос:
У меня есть приложение, которое использует segmentedControl. Первый элемент — это элемент «Все», где остальные создаются из массива на основе результата веб-сервиса. Когда выбрано «Все», я хочу запросить весь запрос.
Как я могу это сделать,
NSArray *urls = [NSArray arrayWithObjects:@"http://service/group/1/",
@"http://service/group/2/", nil];
Я хочу собрать все результаты вызовов в коллекцию и отобразить их в UITableView, когда выбран элемент «Все» и, вероятно, в viewDidLoad.
Для других сегментов выдается только один запрос и выполняется обратный вызов с массивом, который затем используется в:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Я попытался посмотреть на этот пример для выполнения запроса из массива MultipleDownloads
Спасибо,
Метод в моем ViewController для инициирования многократной загрузки:
- (void)requestChildrenInBackground {
queue = [[NSOperationQueue alloc] init];
//Todo remove hard coded and get from previous request respons
NSArray *urls = [NSArray arrayWithObjects: @"http://service/1/children",
@"http://service/2/children",
@"http://service/3/children", nil];
NSLog(@"%@", urls);
for (NSString * url in urls)
{
GetSchedule *operation =
[GetSchedule urlDownloaderWithUrlString:url];
[queue addOperation:operation];
}
}
Вот как обрабатывается множественный запрос:
#import "GetSchedule.h"
#import "JSON.h"
#import "Authentication.h"
#import "AttendanceReportViewController.h"
@interface GetSchedule ()
- (void)finish;
@end
@implementation GetSchedule
@synthesize appDelegate;
@synthesize username;
@synthesize password;
@synthesize authenticationString;
@synthesize encodedLoginData;
@synthesize schedulesArray;
@synthesize url = _url;
@synthesize statusCode = _statusCode;
@synthesize data = _data;
@synthesize error = _error;
@synthesize isExecuting = _isExecuting;
@synthesize isFinished = _isFinished;
(id)urlDownloaderWithUrlString:(NSString *)urlString {
NSURL * url = [NSURL URLWithString:urlString];
GetSchedule *operation = [[self alloc] initWithUrl:url];
return [operation autorelease];
}
- (id)initWithUrl:(NSURL *)url {
self = [super init];
if (self == nil)
return nil;
_url = [url copy];
_isExecuting = NO;
_isFinished = NO;
return self;
}
- (void)dealloc
{
[username release];
[password release];
[encodedLoginData release];
[_url release];
[_connection release];
[_data release];
[_error release];
[super dealloc];
}
- (BOOL)isConcurrent
{
return YES;
}
- (void)start
{
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
return;
}
self.username = appDelegate.username;
self.password = appDelegate.password;
Authentication *auth = [[Authentication alloc] init];
authenticationString = (NSMutableString*)[@"" stringByAppendingFormat:@"%@:%@", username, password];
self.encodedLoginData = [auth encodedAuthentication:authenticationString];
[auth release];
NSLog(@"operation for <%@> started.", _url);
[self willChangeValueForKey:@"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:@"isExecuting"];
// Setup up the request with the url
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:_url];
[request setHTTPMethod:@"GET"];
[request setValue:[NSString stringWithFormat:@"Basic %@", encodedLoginData] forHTTPHeaderField:@"Authorization"];
_connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if (_connection == nil)
[self finish];
else {
_data = [[NSMutableData alloc] init];
}
}
- (void)finish
{
NSLog(@"operation for <%@> finished. "
@"status code: %d, error: %@, data size: %u",
_url, _statusCode, _error, [_data length]);
[_connection release];
_connection = nil;
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
#pragma mark -
#pragma mark NSURLConnection delegate
- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response
{
//[_data release];
//_data = [[NSMutableData alloc] init];
[_data setLength:0];
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
_statusCode = [httpResponse statusCode];
}
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data
{
[_data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Parse the responseData of json objects retrieved from the service
SBJSON *parser = [[SBJSON alloc] init];
NSString *jsonString = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding];
NSDictionary *jsonData = [parser objectWithString:jsonString error:nil];
NSMutableArray *array = [jsonData objectForKey:@"Children"];
schedulesArray = [NSMutableArray array];
[schedulesArray addObject:array];
// Callback to AttendanceReportViewController that the responseData finished loading
[attendanceReportViewController loadSchedule];
[self finish];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
_error = [error copy];
[self finish];
}
@end
Когда все данные получены, я хочу перезвонить моему ViewController и получить массив со всеми данными из всех сделанных запросов.
Комментарии:
1. Я рекомендую библиотеку ASIHTTPRequest , с ее помощью легко ставить в очередь несколько запросов. Перейдите на страницу и выберите, как ее использовать, затем выполните поиск, используя очередь .
2. @Nick ок, спасибо, но из этого я, вероятно, мог бы создать очередь без использования ASIHTTP. На самом деле у меня нет проблем с выполнением запросов относительно добавления результата в ту же коллекцию. Но я предполагаю, что я принял немного воды за голову, когда не использовал ASIHTTP с самого начала. Вероятно, мне нужно добавить полученные данные, а не создавать новый экземпляр NSData для каждого соединения.
3. Я просто предложил ASIHTTP, потому что это проще в использовании, чем NSURLConnections. Однако объединение результатов не должно быть проблемой, при вызове метода делегирования requestFinished просто используйте responseString, в конечном итоге проанализируйте и заполните свою модель.
4. @Nick Я опубликовал код som, чтобы сделать мой вопрос немного более понятным. Я хочу, чтобы по завершении всех запросов выполнялся обратный вызов моему ViewController, который затем может получить массив со всеми данными ответа.
5. Массив пуст, когда я выполняю обратный вызов для его извлечения. Но я не могу передать ViewController, как я делал раньше, методу класса GetSchedule.
Ответ №1:
Создайте загрузчик
- Создайте класс downloader, используя NSURLConnection.
- Сохраните переменную-член с именем downloaderObjectId.
- Напишите метод делегирования для этого объекта. Этот метод передаст загруженные данные и downloaderObjectId обратно делегату.
В делегате.
-
Создайте несколько объектов downloader (в соответствии с вашей необходимостью) с уникальным значением для downloaderObjectId.
-
Сохраните эти объекты в NSMutableDictionary
- Ключом для каждого объекта будет downloaderObjectId. чтобы при вызове метода делегирования после загрузки вы извлекали точный объект обратно из NSMutableDictionary, используя этот ключ.
Основной момент.
-
Каждый раз вызывается делегат. Вы должны удалить объект из словаря (объект, который закончил загрузку и вызвал его delgate. Вы можете идентифицировать этот объект по ключу downloaderObjectId, который он содержит. )
-
Затем проверьте количество словарей. Если оно равно нулю, вы можете убедиться, что ваши загрузки завершены. Таким образом, вы можете вызвать свой viewcontroller.