4

EDIT2 - 質問を書き直しました

バックグラウンドで Web サービス通信を行いたいと考えています。HTTPRequestsのハンドラーとして Sudzc を使用していますが、次のように動作します。

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

XML を Web サービスに送信し、応答 (この例ではブール値) が指定されたセレクターで処理されます。

- (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終了するため、メッセージを送信できません。

4

2 に答える 2

2

これらのリンクSO NURLConnection の質問のリンクの両方から助けがありました。

私のコードにとっては危険ではないようで、自己責任で使用します。ありがとう。

もちろん、どんな推薦も大歓迎です。

時間を割いて助けてくれた Pingbat にさらに感謝します。

于 2012-04-26T13:57:21.443 に答える
2

のメソッド定義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:キューaQueueservice実行され、セレクターが実行されるまで解放されないようにする必要があります。

これには、ポインターを解放できるserviceようにポインターを保持する必要があります。handleOrderSending:また、SudzcWS インスタンスを使用するたびに作成してリリースするのではなく、単一の SudzcWS インスタンスにぶら下がることを検討することもできます。これにより、メモリ管理がはるかに簡単になり、オブジェクト グラフをタイトに保つことができます。

于 2012-04-22T11:52:21.527 に答える