Frage

Ey Jungs, ich lese aus einer plist in strukturiert wie folgt:

property list

Wie Sie sehen können, ist es eine plist die Kommentarinformationen unterschiedlicher Typen (C, Visitor) enthält. Ich kann jeden Annotationstyp Anzeige ganz gut, aber ich bin versucht, durch alle Arten Schleife und alle Anmerkungen auf einmal in der Kartenansicht angezeigt werden soll. Hier ist der Code:

NSLog(@"loadAnnotations");
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"PermitData" ofType:@"plist"];
NSDictionary *rootOfPermitDataPlistDict = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
// NSMutableDictionary *permitDict = [[NSMutableDictionary alloc] init];
 if ([self title] == @"All Permits") {
  for (id key in rootOfPermitDataPlistDict) {
   NSLog(@"key:%@",key);

   //[key retain];
   NSMutableDictionary *permitDict = [NSDictionary dictionaryWithDictionary:[rootOfPermitDataPlistDict objectForKey:key]];
   //[key release];

   //array containing annotation information: latitude, longitude, title, subtitle(see PermitData.plist)
   NSArray *annotationsArray = [[NSArray alloc] initWithArray:[permitDict objectForKey:@"annotations"]];
   [permitDict release];
   [rootOfPermitDataPlistDict release];

   CLLocationCoordinate2D workingCoordinate;
   NSDictionary *annotationContainerDict = [[NSDictionary alloc] init];
   //loop through annotations array, creating parking annotations filled with the information found in the plist
   for(annotationContainerDict in annotationsArray){
    NSLog(@"%@",annotationContainerDict);

    ParkingAnnotation *parkingAnnot = [[ParkingAnnotation alloc] init];
    workingCoordinate.latitude = [[annotationContainerDict objectForKey:@"latitude"] doubleValue];
    workingCoordinate.longitude = [[annotationContainerDict objectForKey:@"longitude"] doubleValue];
    [parkingAnnot setCoordinate:workingCoordinate];
    [parkingAnnot setTitle:[annotationContainerDict objectForKey:@"title"]];
    [parkingAnnot setSubtitle:[annotationContainerDict objectForKey:@"subtitle"]];
    if ([parkingAnnot title] == @"C Parking") [parkingAnnot setAnnotationType:annotationTypeC];
    else if ([parkingAnnot title] == @"Visitor Parking") [parkingAnnot setAnnotationType:annotationTypeVisitor];
    [mapView addAnnotation:parkingAnnot];
    [parkingAnnot release];
   }
   [permitDict release];
  }
 }

Und das ist die Konsole ausgegeben, wenn ich das Programm ausführen:

2010-11-25 03:25:28.020 Parking[38918:207] All Permits
2010-11-25 03:25:28.021 Parking[38918:207] loadAnnotations
2010-11-25 03:25:28.021 Parking[38918:207] key:C
2010-11-25 03:25:28.021 Parking[38918:207] {
    latitude = "38.545301";
    longitude = "-121.754066";
    subtitle = "VP 17";
    title = "C Parking";
}
2010-11-25 03:25:28.022 Parking[38918:207] {
    latitude = "38.544831";
    longitude = "-121.754785";
    subtitle = "VP 16";
    title = "C Parking";
}
2010-11-25 03:25:28.022 Parking[38918:207] {
    latitude = "38.544781";
    longitude = "-121.755729";
    subtitle = "VP 22";
    title = "C Parking";
}
2010-11-25 03:25:28.022 Parking[38918:207] {
    latitude = "38.544412";
    longitude = "-121.752489";
    subtitle = "VP 15";
    title = "C Parking";
}

So ist es die erste NSDictionary Schleifen durch richtig, aber stürzt ab, wenn es im Begriff ist, durch die nächste zu beginnen Looping. Und ich habe versucht, NSDictionary zu NSMutableDictionary ändern, aber das Ergebnis ist das gleiche. Wenn ich also die „Alle Genehmigungen“ Zeile in der Tabelle Ansicht auswählen, es hängt für einen Bruchteil einer Sekunde (ohne in der Kartenansicht schaltend), und dann stürzt, ohne einen Fehler zu erzeugen.

Wenn jemand würde mir nichts dagegen, hier aushelfen, würde ich es sehr schätzen. Vielen Dank im Voraus!

EDIT: Hier ist der Stack-Trace (beschrieben in den Kommentaren unten):

2010-11-25 20:28:08.141 Parking[39400:207] All Permits
2010-11-25 20:28:08.142 Parking[39400:207] loadAnnotations
2010-11-25 20:28:08.142 Parking[39400:207] key:C
2010-11-25 20:28:08.143 Parking[39400:207] {
    latitude = "38.545301";
    longitude = "-121.754066";
    subtitle = "VP 17";
    title = "C Parking";
}
2010-11-25 20:28:08.143 Parking[39400:207] {
    latitude = "38.544831";
    longitude = "-121.754785";
    subtitle = "VP 16";
    title = "C Parking";
}
2010-11-25 20:28:08.143 Parking[39400:207] {
    latitude = "38.544781";
    longitude = "-121.755729";
    subtitle = "VP 22";
    title = "C Parking";
}
2010-11-25 20:28:08.144 Parking[39400:207] {
    latitude = "38.544412";
    longitude = "-121.752489";
    subtitle = "VP 15";
    title = "C Parking";
}
2010-11-25 20:28:08.145 Parking[39400:207] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFDictionary: 0x6d5fd80> was mutated while being enumerated.<CFBasicHash 0x6d5fd80 [0x2667380]>{type = mutable dict, count = 1,
entries =>
    0 : <0x7380> = <NSKeyValueContainerClass: Original class: ParkingAnnotation, Notifying class: NSKVONotifying_ParkingAnnotation>
}
'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x025fdb99 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x0274d40e objc_exception_throw + 47
    2   CoreFoundation                      0x025fd659 __NSFastEnumerationMutationHandler + 377
    3   Parking                             0x00002e93 -[ParkingMapViewController loadAnnotations] + 364
    4   Parking                             0x00002caf -[ParkingMapViewController viewDidLoad] + 117
    5   UIKit                               0x0036a5ca -[UIViewController view] + 179
    6   UIKit                               0x003689f4 -[UIViewController contentScrollView] + 42
    7   UIKit                               0x003787e2 -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:] + 48
    8   UIKit                               0x00376ea3 -[UINavigationController _layoutViewController:] + 43
    9   UIKit                               0x00378067 -[UINavigationController _startTransition:fromViewController:toViewController:] + 326
    10  UIKit                               0x00372ccd -[UINavigationController _startDeferredTransitionIfNeeded] + 266
    11  UIKit                               0x00379d8b -[UINavigationController pushViewController:transition:forceImmediate:] + 876
    12  UIKit                               0x00372b67 -[UINavigationController pushViewController:animated:] + 62
    13  Parking                             0x00002914 -[PermitListViewController tableView:didSelectRowAtIndexPath:] + 307
    14  UIKit                               0x00333a48 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1140
    15  UIKit                               0x0032a32e -[UITableView _userSelectRowAtIndexPath:] + 219
    16  Foundation                          0x0003f21a __NSFireDelayedPerform + 441
    17  CoreFoundation                      0x025def73 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
    18  CoreFoundation                      0x025e05b4 __CFRunLoopDoTimer + 1364
    19  CoreFoundation                      0x0253cdd9 __CFRunLoopRun + 1817
    20  CoreFoundation                      0x0253c350 CFRunLoopRunSpecific + 208
    21  CoreFoundation                      0x0253c271 CFRunLoopRunInMode + 97
    22  GraphicsServices                    0x02edc00c GSEventRunModal + 217
    23  GraphicsServices                    0x02edc0d1 GSEventRun + 115
    24  UIKit                               0x002ceaf2 UIApplicationMain + 1160
    25  Parking                             0x00001e08 main + 102
    26  Parking                             0x00001d99 start + 53
)
terminate called after throwing an instance of 'NSException'

Ich bin jedoch die Freigabe permitDict innerhalb der for-Schleife (zweite [permitDict release] wurde unkommentiert links), so dass ich weiß nicht, warum es beschwert sich über die NSDictionary unveränderlich zu sein. Wie Sie sehen können, ist die permitDict vom Typ NSMutableDictionary, so bin ich verloren, warum es mir diesen Fehler gibt.

War es hilfreich?

Lösung

Der Code ist aus zwei Gründen abstürzt.

Erste , diese Linie, die im Innern ist die for-Schleife:

[rootOfPermitDataPlistDict release];

zerstört das sehr Objekt, das Sie gerade Schleifen. Bewegen Sie es bis zum Ende -. Nach der schließenden Klammer der if ([self title]... Anweisung

Zweite , die beiden Linien, die sagen:

[permitDict release];

sollten entfernt werden. Nicht permitDict freigeben, weil Sie es schaffen dictionaryWithDictionary verwendet, die ein Autoreleased Objekt zurückgibt.

Mit diesen beiden Änderungen sollte der Code ausführen.


Jedoch , gibt es ein paar andere Probleme:

  • Sie alloc + init annotationsArray aber lassen Sie ihn nie (Speicherleck). Lassen Sie es nach der for-Schleife, die durch das Array geht (wo man zur Zeit die zweite [permitDict release]; haben).
  • Sie alloc + init annotationContainerDict aber dann die Variable nur auf die Objekte als Referenz in der annotationsArray (und verlassen so den zugewiesenen Speicher - Speicherleck). Kümmern Sie sich nicht alloc tun + auf annotationContainerDict init, erklären es einfach. Ändern NSDictionary *annotationContainerDict = [[NSDictionary alloc] init]; nur NSDictionary *annotationContainerDict;.
  • Sie vergleichen Strings ==. Verwenden isEqualToString: stattdessen wie folgt aus:
    if ([[self title] isEqualToString:@"All Permits"]).... Für eine Erklärung, warum Sie isEqualToString verwenden sollten, finden Sie diese Frage und diese Frage .
  • Nicht wirklich ein ernstes Problem hier, aber es ist nicht notwendig, dictionaryWithDictionary zu nutzen und so zu duplizieren, was in rootOfPermitDataPlistDict schon da ist. Sie könnten nur permitDict als Abkürzung Verweis auf das eingebettete Wörterbuch wie diese verwenden:. NSMutableDictionary *permitDict = [rootOfPermitDataPlistDict objectForKey:key];
  • Same Punkt mit annotationsArray: Sie müssen nicht zu alloc brauchen + init ein neues Array. Die Anordnung ist bereits in rootOfPermitDataPlistDict. Nehmen Sie einfach einen Verweis auf sie diese mögen: NSArray *annotationsArray = [permitDict objectForKey:@"annotations"];. Nicht annotationsArray freigeben, wenn Sie es auf diese Weise zu tun.

Das Memory Management Programming Guide erklärt alles im Detail.

Andere Tipps

Als erstes gab es viele Probleme mit dem Code, aber es sei denn, diese Leistung ist entscheidend Code, wo man hunderte Male Looping ein zweites werde (was möglicherweise viele Autoreleased Objekte erzeugen können), mit alloc] init] Methode wird nur macht den Code schwerer zu folgen. (Da Sie geistig zu durchlaufen haben und kontinuierlich eine alloc mit einem Release-Balance). Mich nicht falsch, es ist wichtig, dass Sie behalten und Release verstehen, etc., aber das ist die Art, wie ich das Problem nähern würde.

Beachten Sie, dass Sie die Kontrolle haben. Machen Sie Ihre Park Annotation-Klassen der Lage sein, „für sich selbst denken“ ein wenig. In dem folgenden Beispiel habe ich eine - (id) initWithDictionary: so dass Ihre andere Klasse muss nicht dasitzen und alle die Hauptarbeit des Einstellens der Schlüssel eins nach dem anderen zu tun. (Es gibt einige fiktive Teile, wo ich davon ausgehen, würden Sie in die Lücken füllen würde ...

NSString * const PPAnnotationsKey   = @"annotations";
NSString * const PPTitleKey         = @"title";
NSString * const PPSubtitleKey      = @"subtitle";
NSString * const PPLatitudeKey      = @"latitude";
NSString * const PPLongitudeKey     = @"longitude";

NSLog(@"loadAnnotations");
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"PermitData" ofType:@"plist"]; // autoreleased
NSDictionary *permitDictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath]; // autoreleased
if ([[self title] isEqualToString:@"All Permits"]) {
    for (NSString *parkingGroup in permitDictionary) {
        NSLog(@"parkingGroup == %@", parkingGroup);
        NSArray *annotations = [parkingGroup objectForKey:PPAnnotationsKey];
        for (NSDictionary *entry in annotations) {
            PPParkingAnnotation *annotation = [PPParkingAnnotation parkingAnnotationWithDictionary:entry]; // autoreleased
            if (annotation) {
            // assuming here that mapView's addAnnotation: will retain the
            // annotation
            [mapView addAnnotation:annotation]; 
            }
        }
    }
}

@interface PPParkingAnnotation : NSObject <MKAnnotation> {
    CLLocationCoordinate2D   coordinate;
    NSString                *title;
    NSString                *subtitle;
}
+ (id)parkingAnnotationWithDictionary:(NSDictionary *)dictionary;
- (id)initWithDictionary:(NSDictionary *)dictionary;

@properties...
@end

@implementation PPParkingAnnotation

+ (id)parkingAnnotationWithDictionary:(NSDictionary *)dictionary {
    return [[[[self class] alloc] initWithDictionary:dictionary] autorelease];
}

- (id)initWithDictionary:(NSDictionary *)dictionary {
    [self setTitle:[dictionary objectForKey:PPTitleKey]];
    [self setSubtitle:[dictionary objectForKey:PPTitleKey]];
    // and so on.
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top