Question

les gars Ey, je lis depuis un plist structuré comme ceci:

liste de propriétés

Comme vous pouvez le voir, il est un plist qui contient des informations d'annotation de différents types (C, Visiteur). Je peux afficher chaque type d'annotation très bien, mais je tente de boucle à travers tous les types et afficher toutes les annotations sur la vue de la carte à la fois. Voici le 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];
  }
 }

Et ceci est la sortie de la console quand je lance le programme:

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

Il boucle à travers la première NSDictionary correctement, mais tombe en panne quand il est sur le point de commencer une boucle à travers la suivante. Et je l'ai essayé de changer NSDictionary à NSMutableDictionary mais le résultat est le même. Ainsi, lorsque je sélectionne la ligne « Tous les permis » dans l'affichage de la table, il se bloque pendant une fraction de seconde (sans passer à la vue en plan), puis se bloque, sans générer une erreur.

Si quelqu'un ne me dérangerait pas de me aider ici, je serais très heureux. Merci à l'avance!

EDIT: Voici la trace de la pile (décrite dans les commentaires ci-dessous):

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'

Cependant, je publie permitDict au sein de la boucle (deuxième [version permitDict] a été laissé décommentée), donc je ne sais pas pourquoi il se plaint de l'NSDictionary étant immuable. Comme vous pouvez le voir, le permitDict est de type NSMutableDictionary, donc je suis perdu la raison pour laquelle il me donne cette erreur.

Était-ce utile?

La solution

Le code se bloque pour deux raisons principales.

Première , cette ligne qui est à l'intérieur de la boucle for:

[rootOfPermitDataPlistDict release];

détruit l'objet même que vous êtes en train de bouclage. Déplacer à la fin -. Après l'accolade de clôture de l'instruction if ([self title]...

Deuxième , les deux lignes qui disent:

[permitDict release];

doit être supprimé. Ne relâchez pas permitDict parce que vous créez à l'aide dictionaryWithDictionary qui retourne un objet autoreleased.

Avec ces deux changements, le code doit être exécuté.


Cependant , il y a quelques autres problèmes:

  • Vous alloc + initialisation annotationsArray mais jamais le libérer (fuite de mémoire). Relâchez après la boucle for qui passe par ce tableau (où vous avez actuellement la deuxième [permitDict release];).
  • Vous alloc + initialisation annotationContainerDict mais utiliser la variable uniquement comme référence aux objets dans le annotationsArray (et donc l'abandon de la mémoire allouée - fuite de mémoire). Ne vous embêtez pas faire alloc + init annotationContainerDict, déclarer juste. Changement NSDictionary *annotationContainerDict = [[NSDictionary alloc] init]; juste NSDictionary *annotationContainerDict;.
  • Vous comparez des chaînes en utilisant ==. Utilisez isEqualToString: plutôt comme ceci:
    if ([[self title] isEqualToString:@"All Permits"]).... Pour une explication des raisons pour lesquelles vous devriez utiliser isEqualToString, voir cette question et cette question.
  • Pas vraiment un problème grave ici, mais il est inutile d'utiliser dictionaryWithDictionary et dupliquer ainsi ce qui est déjà là dans rootOfPermitDataPlistDict. Vous pouvez simplement utiliser permitDict comme référence de raccourci au dictionnaire intégré comme ceci:. NSMutableDictionary *permitDict = [rootOfPermitDataPlistDict objectForKey:key];
  • Même point avec annotationsArray: vous ne devez alloc + initialiser un nouveau tableau. Le tableau est déjà en rootOfPermitDataPlistDict. Procurez-vous une référence à comme ceci: NSArray *annotationsArray = [permitDict objectForKey:@"annotations"];. Ne relâchez pas annotationsArray si vous décidez de le faire de cette façon.

Le Guide de programmation Gestion de la mémoire explique tout cela en détail.

Autres conseils

Tout d'abord, il y avait beaucoup de problèmes avec votre code, mais une seconde (ce qui pourrait créer de nombreux objets autoreleased) à moins que cela est la performance du code critique, où vous serez mise en boucle des centaines de fois, en utilisant la méthode alloc] init] contenterai faire plus difficile à suivre le code. (Puisque vous devrez mentalement passer et équilibrer en permanence un alloc avec une sortie). Ne vous méprenez pas, il est important que vous compreniez conserver et de la libération, etc., mais c'est la façon dont j'aborder le problème.

Rappelez-vous que vous êtes en contrôle. Faites vos classes d'annotations de stationnement pouvoir « penser pour eux-mêmes » un peu. Dans l'exemple ci-dessous, j'ai ajouté un - (id) initWithDictionary: pour que votre autre classe ne doit pas rester là et faire tout le travail grognement de réglage des touches une par une. (Il y a certaines parties de fiction où je suppose que vous souhaitez remplir les espaces vides ...

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.
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top