2011-01-16 4 views
0

Ich muß sehen, ob ein Objekt, das ich aus einer CSV-Datei mit einer eindeutigen Kennung in meiner Core Data-Datenbank vorhanden ist, erhalten habe, und dies ist der Code, den ich für diese Aufgabe geeignet erachtet:Gibt es eine speichereffizientere Möglichkeit, eine Core Data-Datenbank zu durchsuchen?

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity; 
entity = 
[NSEntityDescription entityForName:@"ICD9" 
      inManagedObjectContext:passedContext]; 
[fetchRequest setEntity:entity]; 
NSPredicate *pred = [NSPredicate predicateWithFormat:@"uniqueID like %@", uniqueIdentifier]; 
[fetchRequest setPredicate:pred]; 
NSError *err; 
NSArray* icd9s = [passedContext executeFetchRequest:fetchRequest error:&err]; 
[fetchRequest release]; 
if ([icd9s count] > 0) { 
    for (int i = 0; i < [icd9s count]; i++) { 
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; 
     NSString *name = [[icd9s objectAtIndex:i] valueForKey:@"uniqueID"]; 
     if ([name caseInsensitiveCompare:uniqueIdentifier] == NSOrderedSame && name != nil) 
     { 
      [pool release]; 
      return [icd9s objectAtIndex:i]; 
     } 
     [pool release]; 
    } 
} 
return nil; 

Nach gründlichem Testen scheint es, dass dieser Code für eine große Menge an Lecks in der App verantwortlich ist, die ich schreibe (es stürzt auf einem 3GS, bevor es 20 Prozent durch die 1459 Elemente macht). Ich denke, das ist nicht der effizienteste Weg, dies zu tun, irgendwelche Vorschläge für einen mehr speichereffizienten Weg? Danke im Voraus!

Antwort

1

Verwenden Sie die Leaks-Schablone in Instruments, um das oder die Lecks zu suchen. Ihr aktueller Code ist möglicherweise in Ordnung, sobald Sie sie behoben haben. Das Leck (die Lecks) können sogar irgendwo anders als Code sein.

Andere Probleme:

  • fast enumeration Verwendung wird die Schleife über das Array (1) schneller und (2) viel leichter lesbar machen.
  • Senden Sie release nicht an einen Autorelease-Pool. Wenn Sie den Code jemals in auf Garbage Collection gesammelten Cocoa portieren, wird der Pool nichts tun. Senden Sie es stattdessen drain; in Retain-Release Cocoa und in Cocoa Touch funktioniert dies genauso wie release, und in Müll gesammelt Kakao, stößt es den Müllsammler, der das nächstgelegene Äquivalent in GC-Land ist, um den Pool zu entwässern.
  • Don't repeat yourself. Sie haben derzeit zwei [pool release]; Zeilen für einen Pool, was jeden erfahrenen Cocoa und Cocoa Touch Programmierer wirklich beunruhigt. Speichern Sie das Ergebnis Ihrer Tests auf den Namen in einer Booleschen Variablen, leeren Sie dann den Pool vor der Bedingung und geben Sie das Objekt dann bedingt zurück.
  • Seien Sie vorsichtig mit Variablentypen. -[NSArray count] zurückkehrt und -[NSArray objectAtIndex:] dauert ein NSUInteger, kein int. Versuchen Sie, alle Ihre Typen immer passend zu halten. (Die Umschaltung auf schnelle Aufzählung löst diese Instanz dieses Problems natürlich auf andere Weise.)
  • Verstecken Sie keine Freigaben. Ich habe dich beinahe beschuldigt, die Abrufanforderung zu verraten, und dann bemerkt, dass du sie in der Mitte des Codes vergraben hast. Machen Sie Ihre Releases prominent, so dass es weniger wahrscheinlich ist, dass Sie versehentlich redundante (d. H. Absturz verursachende) hinzufügen.
+0

Gute Tipps, aber ich würde klären mag: Ich habe zwei Versionen des Pools, weil sie beide Ende in einer Rückkehr, könnten Sie sich selbst machen ein wenig klarer darüber, warum ich nicht zwei von ihnen haben sollte? Außerdem wurde die Abrufanforderung nach der letzten Verwendung freigegeben, sollte ich sie früher freigeben? –

+0

@Kristian: Sie sollten nicht zwei Releases für einen Pool haben, weil Sie beide möglicherweise treffen können. Es ist üblich, dass der Code richtig beginnt, so wie Sie ihn haben, und später falsch gemacht wird, indem eine Rückgabebedingung (oder bedingungslos, die ein Leck verursacht) gemacht oder ersetzt wird. Sich nicht zu wiederholen, vermeidet dieses Problem. Sie müssen den Flow wie vorgeschlagen neu anordnen, um genau eine Anweisung zu erhalten, die den Pool entleert und sicherstellt, dass er immer passiert. –

+0

Wie für die Freigabe der Abrufanforderung, ist mein Vorschlag, es prominent zu veröffentlichen, nicht die Veröffentlichung in der Mitte anderen Code begraben. Sie können es nicht früher freigeben, da Sie es in der unmittelbar vorhergehenden Anweisung verwenden. Sie können es jedoch automatisch freigeben, und genau das tue ich: Autorelease (fast) jedes Objekt sofort nach der Erstellung. –

2
  • Verwenden Sie den like Operator in Ihrer Anfrage Prädikat nicht. Verwenden Sie =. Das sollte viel schneller sein.
  • Sie können die Groß-/Kleinschreibung der Suche über das Vergleichselement mit dem Modifikator [c] angeben.
  • Es ist nicht notwendig, eine NSAutoreleasePool bei jeder Iteration Ihrer Schleife zu erstellen und zu zerstören. In der Tat wird es wahrscheinlich überhaupt nicht benötigt.
  • Sie müssen keine Überprüfung innerhalb der for() Schleife durchführen. Du verdoppelst die Arbeit deines Prädikats.

So würde ich den Code ändern zu sein:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
[fetchRequest setEntity:...]; 
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"uniqueID =[c] %@", uniqueIdentifier]]; 
NSError *err = nil; 
NSArray *icd9s = [passedContext executeFetchRequest:fetchRequest error:&err]; 
[fetchRequest release]; 
if (error == nil && [icd9s count] > 0) { 
    return [icd9s objectAtIndex:0]; //we know the uniqueID matches, because of the predicate 
} 
return nil; 
+0

Sie können auch festlegen, dass, wenn "count" größer als 0 ist, genau 1 zurückgegeben wird. Wenn mehr als eine Übereinstimmung für eine scheinbar eindeutige ID zurückgegeben wird, deutet dies auf fehlerhafte Datenbanken hin. Sie sollten auch testen, ob das Array, nicht das Fehlerobjekt, "Null" ist, wie in der Error-Handling-Programmieranleitung dokumentiert: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/ CreateCustomizeNSError/CreateCustomizeNSError.html% 23 // Apple_ref/doc/uid/TP40001806-CH204-BAJIIGCC –

+0

@Peter die Array-Prüfung ist nicht notwendig, denn wenn 'icd9s' ist 'nil', dann wird' [icd9s count] 'wird 0 zurückgeben, und die 'if()' Bedingung wird fehlschlagen. Ich stimme der Semantik zu, dass die Zählung genau 1 ist. –

+0

@Dave DeLong: Sie können das Array auslassen, indem Sie seine Anzahl testen, aber so oder so, heißt es in der Dokumentation: "Sie sollten immer den Rückgabewert überprüfen ist "nil" ... bevor Sie versuchen, etwas mit dem NSError-Objekt zu tun ". In diesem Fall würde ich das Testen "err" entfernen (und ich würde immer noch explizit überprüfen, dass das Array nicht "nil" ist, aber das ist mein eigener Stil) und eine "else" -Klausel hinzufügen, die den Fehler darstellt. –

Verwandte Themen