Pregunta

chicos Ey, estoy leyendo desde un plist estructurado de esta manera:

lista de propiedades

Como se puede ver, se trata de un plist que contiene la anotación de información de diferentes tipos (C, Visitante). Puedo mostrar cada tipo de anotación muy bien, pero estoy tratando de bucle a través de todos los tipos y mostrar todas las anotaciones en la vista del mapa a la vez. Aquí está el código:

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

Y esta es la salida de la consola cuando corro el programa:

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

Así se realiza un bucle a través de la primera NSDictionary correctamente, pero se bloquea cuando está a punto de comenzar bucle a través de la siguiente. Y he intentado cambiar NSDictionary a NSMutableDictionary pero el resultado es el mismo. Así que cuando selecciono la fila "todos los permisos" en la vista de tabla, se cuelga por una fracción de un segundo (sin cambiar a la vista de mapa), y luego se bloquea, sin generar un error.

Si alguien no le importaría ayudarme aquí, sería de gran aprecio. Gracias de antemano!

EDIT: Aquí está el seguimiento de la pila (descrito en los comentarios a continuación):

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'

Sin embargo, yo estoy liberando permitDict dentro del bucle (segundo [liberación permitDict] que quedaba sin comentar), así que no sé por qué se quejan de la NSDictionary ser inmutable. Como se puede ver, el permitDict es de tipo NSMutableDictionary, por lo que estoy perdido en cuanto a porqué me está dando este error.

¿Fue útil?

Solución

El código se bloquea por dos razones principales.

Primera , esta línea que está dentro del bucle for:

[rootOfPermitDataPlistDict release];

destruye el objeto que actualmente está recorriendo. Moverlo hasta el final -. Después de la llave de cierre del estado if ([self title]...

Segundo , las dos líneas que dicen:

[permitDict release];

debe ser eliminado. No suelte permitDict porque va a crear usando dictionaryWithDictionary que devuelve un objeto autoreleased.

Con estos dos cambios, el código debería funcionar.


No obstante , hay algunos otros problemas:

  • alloc annotationsArray + init pero nunca lo suelte (pérdida de memoria). Liberarlo después de que el ciclo for que pasa por esa matriz (donde actualmente tiene la segunda [permitDict release];).
  • alloc annotationContainerDict + init pero luego utilizar la variable sólo como una referencia a los objetos en el annotationsArray (y así abandonar la memoria asignada - pérdida de memoria). No se moleste en hacer alloc + INIT en annotationContainerDict, solo declararlo. Cambio NSDictionary *annotationContainerDict = [[NSDictionary alloc] init]; sólo NSDictionary *annotationContainerDict;.
  • Usted está comparando secuencias utilizando ==. Uso isEqualToString: lugar como esto:
    if ([[self title] isEqualToString:@"All Permits"]).... Para una explicación de por qué debería utilizar isEqualToString, consulte esta pregunta y esta pregunta .
  • No es realmente un problema serio aquí, pero no es necesario utilizar dictionaryWithDictionary y así duplicar lo que ya existe en rootOfPermitDataPlistDict. Se podía utilizar permitDict como una forma abreviada de referirse al diccionario incorporado como esto:. NSMutableDictionary *permitDict = [rootOfPermitDataPlistDict objectForKey:key];
  • mismo punto con annotationsArray: no es necesario que alloc + init una nueva matriz. La matriz ya está en rootOfPermitDataPlistDict. Acaba de obtener una referencia a él como esto: NSArray *annotationsArray = [permitDict objectForKey:@"annotations"];. No suelte annotationsArray si decide hacerlo de esta manera.

El Gestión de Memoria Guía de Programación explica todo esto en detalle.

Otros consejos

En primer lugar, había muchos problemas con su código, pero a menos que éste es el rendimiento del código crítico, donde se le bucle a cientos de veces por segundo (lo que potencialmente podría crear muchos objetos autoreleased), utilizando alloc] init método] se acaba hacer que el código sea más difícil de seguir. (Puesto que usted tiene que ir a través mental y continuamente equilibrar un alloc con un lanzamiento). No me malinterpreten, es importante que entienda retener y liberación, etc., pero esta es la forma en que iba a abordar el problema.

Recuerde que usted está en control. Haga que sus clases de anotación de estacionamiento sean capaces de "pensar por sí mismos" un poco. En el siguiente ejemplo, he añadido un - (id) initWithDictionary: para que su otra clase no tiene que sentarse allí y hacer todo el trabajo sucio de establecer las claves de uno en uno. (Hay algunas partes de ficción donde me gustaría suponer que le llenó los espacios ...

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.
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top