Методы делегата NSURLConnection в фоновом потоке

EDIT2 - переписал вопрос

Я хочу сделать некоторые веб-службы связи в фоновом режиме. Я использую Sudzc в качестве обработчика HTTPRequests, и он работает так:

SudzcWS *service = [[SudzcWS alloc] init];
[service sendOrders:self withXML:@"my xml here" action:@selector(handleOrderSending:)];
[service release];

Он отправляет некоторый XML в веб-сервис, и ответ (в данном случае логический) обрабатывается в указанном селекторе:

- (void)handleOrderSending:(id)value
{ 
//some controls  
    if ([value boolValue] == YES)
    {
        //my stuff
    }
}

Когда я попытался использовать Grand Central Dispatch на своем sendOrders:withXML:action: Методом я заметил, что селектор не вызывается. И я полагаю, что причина этого в том, что сообщения делегата NSURLConnection отправляются в поток, для которого создано соединение. Но поток не живет так долго, он заканчивается, когда метод завершается, убивая любые сообщения делегату.

С уважением

EDIT1[request send] метод:

- (void) send {
//dispatch_async(backgroundQueue, ^(void){
    // If we don't have a handler, create a default one
    if(handler == nil) {
        handler = [[SoapHandler alloc] init];
    }

    // Make sure the network is available
    if([SoapReachability connectedToNetwork] == NO) {
        NSError* error = [NSError errorWithDomain:@"SudzC" code:400 userInfo:[NSDictionary dictionaryWithObject:@"The network is not available" forKey:NSLocalizedDescriptionKey]];
        [self handleError: error];
    }

    // Make sure we can reach the host
    if([SoapReachability hostAvailable:url.host] == NO) {
        NSError* error = [NSError errorWithDomain:@"SudzC" code:410 userInfo:[NSDictionary dictionaryWithObject:@"The host is not available" forKey:NSLocalizedDescriptionKey]];
        [self handleError: error];
    }

    // Output the URL if logging is enabled
    if(logging) {
        NSLog(@"Loading: %@", url.absoluteString);
    }

    // Create the request
    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL: url];
    if(soapAction != nil) {
        [request addValue: soapAction forHTTPHeaderField: @"SOAPAction"];
    }
    if(postData != nil) {
        [request setHTTPMethod: @"POST"];
        [request addValue: @"text/xml; charset=utf-8" forHTTPHeaderField: @"Content-Type"];
        [request setHTTPBody: [postData dataUsingEncoding: NSUTF8StringEncoding]];

        if(self.logging) {
            NSLog(@"%@", postData);
        }
    }


    //dispatch_async(dispatch_get_main_queue(), ^(void){
        // Create the connection
        conn = [[NSURLConnection alloc] initWithRequest: request delegate: self];
        if(conn) {
                                        NSLog(@" POST DATA %@", receivedData);
            receivedData = [[NSMutableData data] retain];
                        NSLog(@" POST DATA %@", receivedData);
        } else {
            // We will want to call the onerror method selector here...
            if(self.handler != nil) {
                NSError* error = [NSError errorWithDomain:@"SoapRequest" code:404 userInfo: [NSDictionary dictionaryWithObjectsAndKeys: @"Could not create connection", NSLocalizedDescriptionKey,nil]];
                [self handleError: error];
            }
        }
    //});


    //finished = NO;

    //    while(!finished) {
    //        
    //        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    //        
    //    }

//});
}

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

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSError* error;
if(self.logging == YES) {
    NSString* response = [[NSString alloc] initWithData: self.receivedData     encoding: NSUTF8StringEncoding];
    NSLog(@"%@", response);
    [response release];
}

CXMLDocument* doc = [[CXMLDocument alloc] initWithData: self.receivedData options: 0 error: &error];
if(doc == nil) {
    [self handleError:error];
    return;
}

id output = nil;
SoapFault* fault = [SoapFault faultWithXMLDocument: doc];

if([fault hasFault]) {
    if(self.action == nil) {
        [self handleFault: fault];
    } else {
        if(self.handler != nil && [self.handler respondsToSelector: self.action]) {

                [self.handler performSelector: self.action withObject: fault];


        } else {
            NSLog(@"SOAP Fault: %@", fault);
        }
    }
} else {
    CXMLNode* element = [[Soap getNode: [doc rootElement] withName: @"Body"] childAtIndex:0];
    if(deserializeTo == nil) {
        output = [Soap deserialize:element];
    } else {
        if([deserializeTo respondsToSelector: @selector(initWithNode:)]) {
            element = [element childAtIndex:0];
            output = [deserializeTo initWithNode: element];
        } else {
            NSString* value = [[[element childAtIndex:0] childAtIndex:0] stringValue];
            output = [Soap convert: value toType: deserializeTo];
        }
    }

    if(self.action == nil) { self.action = @selector(onload:); }
    if(self.handler != nil && [self.handler respondsToSelector: self.action]) {


            [self.handler performSelector: self.action withObject: output];


    } else if(self.defaultHandler != nil && [self.defaultHandler respondsToSelector:@selector(onload:)]) {
        [self.defaultHandler onload:output];
    }
}

[self.handler release];
[doc release];
[conn release];
conn = nil;
[self.receivedData release];
}

Делегат не может отправлять сообщения, потому что поток, который он умирает, когда -(void)send отделки.

2 ответа

Решение

Я получил помощь как от этих ссылок так NURLConnection вопрос и оригинал.

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

Любые рекомендации все еще приветствуются, конечно.

Еще одно спасибо Пингбату за то, что он нашел время, чтобы попытаться помочь.

Определение метода для sendOrders предполагает, что он уже предназначен для выполнения запросов в асинхронном режиме. Вы должны посмотреть на реализацию sendOrders: withXML: action: чтобы узнать, если это так.

Не видя своей реализации с использованием GCD или кода из SudzcWS, трудно сказать, что происходит не так. Несмотря на предыдущие предостережения, могут быть полезны следующие.

Похоже, вы выпускаете SudzcWS *service до его завершения.

Следующие:

SudzcWS *service = [[SudzcWS alloc] init];
dispatch_async(aQueue, ^{
    [sevice sendOrders:self withXML:xml action:@selector(handleOrderSending:)];
}
[service release];

может потерпеть неудачу, если SudzcWS не сохранится. Вы отправляете свой блок асинхронно, он помещается в очередь, и выполнение метода продолжается. service освобождается и освобождается до выполнения блока или во время service ждет ответа от веб-сервера.

Если не указано иное, вызов селектора выполнит этот селектор в том же потоке, в котором он вызывается. Делать что-то вроде:

SudzcWS *service = [[SudzcWS alloc] init];
dispatch_async(aQueue, ^{
    [sevice sendOrders:self withXML:xml action:@selector(handleOrderSending:)];
}


- (void)handleOrderSending:(id)value
{ 
    //some controls  
    //your stuff
    [service release];
}

следует убедиться, что оба sendOrders: метод и handleOrderSending: выполняются в очереди aQueue и это service не освобождается, пока не выполнит селектор.

Это потребует от вас сохранить указатель на service чтобы handleOrderSending: может выпустить это. Возможно, вы захотите просто повесить на один экземпляр SudzcWS вместо того, чтобы создавать и выпускать его каждый раз, когда вы захотите его использовать, это должно значительно упростить управление памятью и сохранить плотный график объектов.

Другие вопросы по тегам