iPhone: обработка двух (или нескольких) ответов на два запроса в одном и том же делегате. - PullRequest
0 голосов
/ 11 февраля 2012

Я вызываю вызовы асинхронных методов NSURLConnection в моем контроллере представления.Я хотел бы обработать ДВЕ ОТВЕТА НА ДВА ЗАПРОСА в том же делегате.Пожалуйста, предложите мне, каков наилучший подход для достижения этой цели?Я разрабатываю в iOS 5 SDK.

ОБНОВЛЕНО:

 // Class A
 [serverconns setDelegate:self];
 connection = [serverconns executeAsyncHttpPost :firstjsonrequest];

 [serverconns setDelegate:self];
 connection = [serverconns executeAsyncHttpPost :secondjsonrequest];


- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
}

- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [self.appendData appendData:data];
}

- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    // logs the error
}

- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSData *responseData = [[NSData alloc] initWithData:appendData];
    //HOW CAN WE HANDLE TWO RESPONSES FOR TWO REQUEST in the same Delegate
    if (responseData) 
    {
          // doing something
    }
}

    //Class B: ServerConnection

- (NSURLConnection *) executeAsyncHttpPost :(id) jsonParams
{
    NSString *urlstr = [NSString stringWithFormat:@"%@", baseURL];
    urlstr = [urlstr stringByAppendingFormat:method];

    NSURL *pUrl = [NSURL URLWithString:urlstr];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:pUrl];
    NSData *requestData = [NSData dataWithBytes:[jsonParams UTF8String] length:[jsonParams length]];

    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-type"];
    [request setHTTPBody: requestData];

    return [[NSURLConnection alloc] initWithRequest:request delegate:delegateResponder startImmediately:YES];

}
    -(void) setDelegate:(id)newDelegate
{
    delegateResponder = newDelegate;
}

Ответы [ 5 ]

3 голосов
/ 11 февраля 2012

где-нибудь сохраните свои соединения (возможно, ivar вашего делегата)

- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSData *responseData = [[NSData alloc] initWithData:appendData];
    //HOW CAN WE HANDLE TWO RESPONSES FOR TWO REQUEST in the same Delegate
    if (responseData) 
    {
        if (connection == yourFirstConnection) {
            // doing something for first connection
        } else {
            // doing something for second connection
        }
    }
}

просто укажите на небольшую проблему вашего кода

NSString *urlstr = [NSString stringWithFormat:@"%@", baseURL];
urlstr = [urlstr stringByAppendingFormat:method];

следует заменить на

NSString *urlstr = [baseURL absoluteString];
urlstr = [urlstr stringByAppendingString:method];

и добавьте два (или более или массив) слабых / назначить свойство NSURLConnection вашему классу A (делегат соединения)

@property (assign) NSURLConnection *myFirstConnection;
@property (assign) NSURLConnection *mySecondConnection;
// assume only need to handle two connection otherwise NSArray should be used instead

чем в вашем классе B (создать соединение)

- (NSURLConnection *) executeAsyncHttpPost :(id) jsonParams
{
    NSString *urlstr = [baseURL absoluteString];
    urlstr = [urlstr stringByAppendingString:method];

    NSURL *pUrl = [NSURL URLWithString:urlstr];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:pUrl];
    NSData *requestData = [NSData dataWithBytes:[jsonParams UTF8String] length:[jsonParams length]];

    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-type"];
    [request setHTTPBody: requestData];

    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegateResponder startImmediately:YES];
    delegateResponder.myFirstConnection = connection;
    // delegateResponder.mSecondConnection = connection;
    return connection;

}
2 голосов
/ 11 февраля 2012

На вашем месте я бы создал CustomClass, который наследует NSURLConnection.И я добавлю свойство с именем tag.

Когда я инициирую CustomClass, я бы установил свойство tag и использовал его, чтобы определить, над каким запросом выполняется

CustomURLConnection *connection = [[CustomURLConnection alloc] initWithRequest:request delegate:self tag:1];

- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate   tag:(int)_tag
 {
if(self = [super initWithRequest:request delegate:delegate])
{   
   self.tag = _tag;
}

Теперь в кодеВы добавили это

- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSData *responseData = [[NSData alloc] initWithData:appendData];
    //HOW CAN WE HANDLE TWO RESPONSES FOR TWO REQUEST in the same Delegate
    if (responseData) 
    {
      if (connection.tag == 1){

      }
    }
}

return self;
  }
1 голос
/ 11 февраля 2012

Я думаю, что все упомянутые решения "безобразны". Я бы не стал реализовывать решение с помощью методов делегатов, а вместо этого создал бы решение на основе блоков. Я мог бы опубликовать пример, если вам интересно. Для этого подхода я бы использовал классы AFNetworking .


Ниже приведен пример класса, который обрабатывает 2 разных ответа без использования реализации делегата, вместо этого выбирая блоки с библиотекой AFNetworking.

- (void)JSONFromService
{
    // create the first request and set the methods that handle the return values (either NSData or NSError in this case) in blocks ... 

    NSURL *firstURL = [NSURL URLWithString:@"http://dl.dropbox.com/u/6487838/test1.html"];
    NSURLRequest *firstRequest = [NSURLRequest requestWithURL:firstURL];
    AFHTTPRequestOperation *firstOperation = [[AFHTTPRequestOperation alloc] initWithRequest:firstRequest];

    [firstOperation setCompletionBlockWithSuccess:^ (AFHTTPRequestOperation *operation, id object) 
    {
        NSString *firstString = [[NSString alloc] initWithData:object encoding:NSASCIIStringEncoding];
        NSLog(@"%@", firstString);
    } failure:^ (AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"%@", error);
    }];
    [firstOperation start];



    // create the second request and set the methods that handle the return values (either NSData or NSError in this case) in blocks ... 

    NSURL *secondURL = [NSURL URLWithString:@"http://dl.dropbox.com/u/6487838/test2.html"];
    NSURLRequest *secondRequest = [NSURLRequest requestWithURL:secondURL];
    AFHTTPRequestOperation *secondOperation = [[AFHTTPRequestOperation alloc] initWithRequest:secondRequest];

    [secondOperation setCompletionBlockWithSuccess:^ (AFHTTPRequestOperation *operation, id object) {
        NSString *secondString = [[NSString alloc] initWithData:object encoding:NSASCIIStringEncoding];
        NSLog(@"%@", secondString);
    } failure:^ (AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"%@", error);
    }];
    [secondOperation start];
}
0 голосов
/ 11 февраля 2012

Я думаю, вы должны хранить все свои соединения в массиве activeConnections. Каждый раз, когда кто-то заканчивает, вы делаете [activeConnections indexForObject:connection] и соответственно обновляете свой метод делегата, используя индекс.

Теперь, более чистый способ сделать это (и лучший, с моей точки зрения, способ, но это зависит от размера данных, которые вы хотите передать) - это использовать очереди. Я приведу небольшой пример и добавлю к нему комментарии:

// we assume you have 2 requests: req1, req2

//now, create a new dispatch queue    
dispatch_queue_t netQueue = dispatch_queue_create("com.mycompany.netqueue",DISPATCH_QUEUE_SERIAL);

//execute the operations in the queue ASYNC
//is very important to dispatch this ASYNC on a background thread, otherwise your UI will be stuck until the request finishes 
dispatch_async(netQueue, 
^{
  // We are on a background thread, so we won't block UI events (or, generally, the main run loop)
  NSHTTPURLResponse *response = nil;
  NSError *error = nil;
  NSData *data = nil;




  //We can call the request synchronous and block this thread until completed
  data = [NSURLConnection sendSynchronousRequest:req1
                               returningResponse:&response 
                                           error:&error];

  dispatch_async(dispatch_get_main_queue(),
  ^{
    //call your delegate with the appropriate method for req1 
    //be sure to copy the contents in data, as we will reuse it with the next request 
  });

  //We can call the other request synchronous and block this thread until completed
  data = [NSURLConnection sendSynchronousRequest:req2
                               returningResponse:&response 
                                           error:&error];
  dispatch_async(dispatch_get_main_queue(),
  ^{
  //call your delegate with the appropriate method for req2 
  });




  //and this can go on forever. If you have many requests to execute, simply put them in a loop


 });
 dispatch_release(netQueue);
0 голосов
/ 11 февраля 2012

Я обычно создаю подкласс NSURLConnection и добавляю свойства для хранения любого контекста, который мне нужен для обработки ответа.

Поскольку методы делегата передают NSURLConnection, вы можете просто привести его обратно к своему подклассу и получить доступ к контексту.

Взгляните на этот пример .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...