2014-02-25 9 views
17

Ich habe ein Array, das ich durchsuche und nach einem bestimmten Flag suche. Wenn der Flag-Wert Null ist, rufe ich eine Methode auf, die ein Aufrufobjekt erzeugt und das Ergebnis des Aufrufs zurückgibt.NSInvocation gibt Wert zurück, aber App stürzt ab mit EXC_BAD_ACCESS

My Codestruktur ist als

for(NSString *key in [taxiPlanes allKeys]) 
{ 
     Plane *currentPlane = [taxiPlanes objectForKey:key]; 

     if(currentPlane.currentAction == nil) 
     { 
      NSString *selector = [[currentPlane planeTakeoffSequence] firstObject]; 
      currentPlane.currentAction = selector; 

      // Calling for NSInvocation in [self ...] 
      NSArray *action = [NSArray arrayWithArray:[self operationFromTakeoffAction:currentPlane.currentAction AtPoint:currentPlane.position]]; 

     NSLog(@"%@",action); 
     } 
} 

Methode, die NSInvocation

-(NSArray *) operationFromTakeoffAction:(NSString *) action AtPoint:(CGPoint) flightPoint 
{ 
    NSMethodSignature *methodSignature = [FlightOperations instanceMethodSignatureForSelector:NSSelectorFromString(action)]; 
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; 

    [invocation setTarget:fOps]; 
    [invocation setSelector:NSSelectorFromString(action)]; 
    [invocation setArgument:&flightPoint atIndex:2]; 

    NSArray *resultSet = [NSArray alloc]init]; 
    [invocation invoke]; 
    [invocation getReturnValue:&resultSet]; 

    return resultSet; 
} 

In der for-Schleife erzeugt folgt, ohne den Methodenaufruf für NSInvocation ([self ....]), der Die Schleife wird einfach ausgeführt und stürzt nicht ab. Aber wenn ich die Methode zum Aufrufen von NSInvocation einführe, kann ich sehen, dass NSLog in für den Ausdruck das erwartete NSArray-Ergebnis druckt, aber es stürzt mit der Fehlermeldung EXC_BAD_ACCESS ab.

Ich kann nicht herausfinden, warum es fehlschlägt, obwohl NSInvocation ordnungsgemäßes Ergebnis zurückgibt. Ohne NSInvocation wird for-Schleife nicht abgestürzt.

Alle Vorschläge wären hilfreich.

Danke

+0

haben Sie weitere Informationen haben auf zu diskutieren, sagte sein der Absturzgrund von der Konsole oder vom Debugger? – Volker

+1

Die Konsole zeigt keine weiteren Informationen an. Alles, was ich bekomme, ist Thread 1: EXC_BAD_ACCESS (code = EXC_i386_GPFLT) – slysid

+1

Setup NSZombieEnabled. Es gibt Ihnen mehr Informationen. Siehe http://stackoverflow.com/questions/2190227/how-do-i-set-up-nszombeenenabled-in-xcode-4 – asgoth

Antwort

65

Ich vermute, Sie verwenden ARC?

Das Problem ist mit der Linie [invocation getReturnValue:&resultSet];. getReturnValue: kopiert nur die Bytes des Rückgabewerts in den angegebenen Speicherpuffer, unabhängig vom Typ. Die Speicherverwaltung ist nicht bekannt oder wichtig, wenn der Rückgabetyp ein beibehaltener Objekt-Zeigertyp ist. Da resultSet eine Variable des Objekt-Zeigertyps ist, nimmt ARC an, dass ein beliebiger Wert, der in die Variable eingegeben wurde, beibehalten wurde, und wird ihn daher freigeben, wenn er den Gültigkeitsbereich verlässt. Das stimmt in diesem Fall nicht, also stürzt es ab. (Auch das Array, das Sie resultSet ursprünglich Punkt hatten wird geleckt werden, da getReturnValue: diesen Wert überschreibt, ohne sie zu veröffentlichen. Warum Sie selbst gemacht, dass variable Punkt auf ein Objekt in erster Linie über mich.)

Die Lösung ist, dass Sie einen Zeiger auf einen nicht beibehaltenen Typ getReturnValue: geben müssen. Entweder:

NSArray * __unsafe_unretained tempResultSet; 
[invocation getReturnValue:&tempResultSet]; 
NSArray *resultSet = tempResultSet; 

oder:

void *tempResultSet; 
[invocation getReturnValue:&tempResultSet]; 
NSArray *resultSet = (__bridge NSArray *)tempResultSet; 
+3

Ich hatte das gleiche Problem, und diese Lösung arbeitete wie ein Charme! :) –

+4

Riesige Umarmungen und Küsse dafür. – mxcl

+0

@newacct Kumpel! Ich roch etwas falsch mit meiner Anrufung, aber, wie es oft passiert, eilt man zu viel, um die Dokumentation durchzulesen und zu denken ... vielen Dank! – peetonn

1

Ja, das ist happenedIn nur die ARC

Ich denke, das ist das System Bug..

Zum Beispiel:
【iPhone4s + iOS8.4】, 【iphone 4 + iOS7.1】 (Crash),
【iPhone6 ​​+ iOS9.3】, 【iphone 5 + iOS8.4.1】 (Pass),

mein Test Demo Download-Link https://github.com/leopardpan/IssuesDemo

Der ursprüngliche Code

NSArray *resultSet = [NSArray alloc]init]; 
[invocation invoke]; 
[invocation getReturnValue:&resultSet]; 

folgenden

Fall 1 zu lösen:

void *temp = NULL; 
[invocation invoke]; 
[invocation getReturnValue:&temp]; 
NSArray *resultSet = (__bridge NSArray*)temp; 

Fall 2 :

__weak NSArray *resultSet = [NSArray alloc]init]; 
[invocation invoke]; 
[invocation getReturnValue:&resultSet]; 

Fall 3:

__autoreleasing NSArray *resultSet = [NSArray alloc]init]; 
[invocation invoke]; 
[invocation getReturnValue:&resultSet]; 

Fall 4:

__unsafe_unretained NSArray *resultSet = [NSArray alloc]init]; 
[invocation invoke]; 
[invocation getReturnValue:&resultSet]; 

Empfohlen case1 zu verwenden, sollten Prinzip @newacct
Willkommen