SudzC ARC version - wywołanie objc_msgSend powoduje EXC_BAD_ACCESS przy użyciu architektury 64-bitowej

Edycja - śledziłem poniższy problem w 64-bitowym kontra 32-bitowym problemie architektury ... zobacz moją wysłaną odpowiedź dotyczącą rozwiązania

UżyłemSudzC wygenerować kod SOAP dla usługi internetowej. Dostarczają one przykładowej aplikacji, z której mogłem z powodzeniem korzystać zarówno na urządzeniu, jak i na symulatorze.

Potem zacząłem budować moją aplikację. Zaimportowałem pliki wygenerowane przez SudzC do nowego projektu XCode przy użyciu pustego szablonu aplikacji (z włączonym CoreData i ARC).

Pierwsze żądanie SOAP zostało uruchomione i uruchomione - wszystko działa w symulatorze - a potem poszedłem na pierwszy test na urządzeniu (iPhone 5S z systemem iOS 7.02). Urządzenie rzucaEXC_BAD_ACCESS błąd przy każdym uruchomieniu żądania SOAP.

Śledziłem to doSoapRequest.m plik, a konkretnieconnectionDidFinishLoading metoda. Ta metoda używa aobjc_msgSend wywołanie, aby wysłać dane odpowiedzi SOAP z powrotem do metody obsługi w innej klasie (w tym przypadku kontrolera widoku). Oto kod:

SoapRequest.m:

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

    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]) {
                objc_msgSend(self.handler, self.action, 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]) {
            objc_msgSend(self.handler, self.action, output);
        } else if(self.defaultHandler != nil && [self.defaultHandler respondsToSelector:@selector(onload:)]) {
            [self.defaultHandler onload:output];
        }

    }
    conn = nil;
}

Więc liniaobjc_msgSend(self.handler, self.action, output); wydaje się być tam, gdzie jest mój problem.self.handler wskazuje na mój kontroler widoku iself.action wskazuje na tę metodę:

TasksViewController.m:

- (void) findItemHandler: (id) value {

    // Handle errors
    if([value isKindOfClass:[NSError class]]) {
        NSLog(@"%@", value);
        return;
    }

    // Handle faults
    if([value isKindOfClass:[SoapFault class]]) {
        NSLog(@"%@", value);
        return;
    }

    // Do something with the id result
    NSLog(@"FindItem returned the value: %@", value);
}

Ponowne wejście do tej metody to miejsce, w którym się rozwalam. Wygląda jak(id)value nie robi tego z klasy SoapRequest. Zakładam, że zostaje zwolniony przez ARC. Przetestowałem połączenie, zastępując je(id)value zint:

objc_msgSend(self.handler, self.action, 1);

i

- (void)findItemHandler:(int)value

To działa. Zakładając, że problem polega na tym, że zmienna wartości zostaje przedwcześnie zniszczona, spróbowałem kilku rzeczy, aby ją zachować. Dodałem właściwość do SoapRequest.m:

@property (nonatomic, strong) id value;

Potem minęło:

self.value = output;
objc_msgSend(self.handler, self.action, self.value);

Taki sam problem. Próbowałem też tego samego z instancją SoapRequest ... Teraz mogłem obejść ten problem, tworząc właściwość w kontrolerze widoku i ustawiając tę ​​właściwość na wartość, ale jestem naprawdę ciekawy, jak to naprawić oryginalny kod. Wróciłem do przykładowej aplikacji pobranej z SudzC, aby zobaczyć, jak to działa, i okazało się, że ARC nie jest włączone dla tego projektu (!).

Czy ktoś może mi powiedzieć:

1) Jeśli mam rację, w moim założeniu, żeoutput jest zwalniany, powodując, że metoda obsługi odwołuje się do złego adresu pamięci?

2) Dlaczego to działa na symulatorze? Zakładam, że jest tak, ponieważ sim ma dużo więcej pamięci, więc nie jest tak agresywny w przypadku deallocations ARC ...

3) Jak mogłem to naprawić, zakładając, że chcę zachowaćobjc_msgSend połączenie? Chcę się dowiedzieć, jak to się dzieje

4) Jeśli SudzC jest w tym miejscu poprawnyobjc_msgSend, jak rozumiem, złym zwyczajem jest nazywanie tego bezpośrednio, z wyjątkiem rzadkich okoliczności?

Dzięki!

questionAnswers(1)

yourAnswerToTheQuestion