SudzC ARC-Version - objc_msgSend-Aufruf verursacht EXC_BAD_ACCESS unter Verwendung einer 64-Bit-Architektur

Bearbeiten - Ich habe das folgende Problem in ein 64-Bit- oder 32-Bit-Architekturproblem umgewandelt. Wie ich es gelöst habe, erfahren Sie in meiner Antwort

Ich habe benutztSudzC SOAP-Code für einen Webdienst generieren. Sie liefern Ihnen eine Beispielanwendung, die ich sowohl auf dem Gerät als auch auf dem Simulator erfolgreich einsetzen konnte.

Ich habe dann angefangen, meine App auszubauen. Ich habe die von SudzC generierten Dateien mithilfe der leeren Anwendungsvorlage (mit aktivierten CoreData- und ARC-Funktionen) in ein neues XCode-Projekt importiert.

Ich habe die erste SOAP-Anforderung eingerichtet und ausgeführt - alles funktioniert im Simulator - und dann habe ich meinen ersten Test auf einem Gerät (iPhone 5S mit iOS 7.02) durchgeführt. Das Gerät wirft einEXC_BAD_ACCESS Fehler bei jeder Ausführung der SOAP-Anforderung.

Ich habe das aufgespürtSoapRequest.m Datei, speziell dieconnectionDidFinishLoading Methode. Diese Methode verwendet aobjc_msgSend call, um die SOAP-Antwortdaten an eine Handlermethode in einer anderen Klasse (in diesem Fall my view controller) zurückzusenden. Hier ist der Code:

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;
}

Also die Leitungobjc_msgSend(self.handler, self.action, output); scheint dort zu sein, wo mein Problem ist.self.handler zeigt auf meinen View Controller undself.action verweist auf diese Methode:

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);
}

Der Wiedereinstieg in diese Methode ist, wo ich abstürze. Es sieht aus wie der(id)value macht es nicht aus der SoapRequest-Klasse. Ich nehme an, es wird von ARC freigegeben. Ich habe den Anruf durch Ersetzen getestet(id)value mit einemint:

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

und

- (void)findItemHandler:(int)value

Das funktioniert. Angenommen, das Problem ist, dass die Wertvariable vorzeitig zerstört wird, habe ich ein paar Dinge versucht, um sie beizubehalten. Ich habe SoapRequest.m eine Eigenschaft hinzugefügt:

@property (nonatomic, strong) id value;

Dann bestanden, dass:

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

Gleiches Problem. Ich habe dasselbe auch mit der Instanz von SoapRequest versucht ... Jetzt konnte ich das Problem umgehen, indem ich eine Eigenschaft im Ansichts-Controller erstellte und diese Eigenschaft auf den Wert festlegte, aber ich bin wirklich neugierig, wie dies mit behoben werden kann der ursprüngliche Code. Ich kehrte zu der Beispiel-App zurück, die ich von SudzC heruntergeladen hatte, um zu sehen, wie das funktioniert, und es stellte sich heraus, dass ARC für dieses Projekt nicht aktiviert ist (!).

Kann mir jemand sagen:

1) Wenn ich das richtig annehmeoutput wird die Zuordnung aufgehoben, wodurch die Handlermethode auf eine ungültige Speicheradresse verweist?

2) Warum funktioniert das auf dem Simulator? Ich nehme an, es liegt daran, dass die Sim viel mehr Speicher zur Verfügung hat, so dass es nicht so aggressiv mit ARC-Aufhebungen ist ...

3) Wie ich das beheben könnte, vorausgesetzt ich möchte das behaltenobjc_msgSend Anruf? Ich möchte erfahren, wie / warum dies geschieht

4) Wenn SudzC in ihrer Verwendung hier von richtig istobjc_msgSend, wie ich verstehe, ist es schlechte Praxis, dies nur in seltenen Fällen direkt anzurufen?

Vielen Dank!

Antworten auf die Frage(1)

Ihre Antwort auf die Frage