Ios 通过从属性列表读取的NSDictionary进行循环会带来麻烦

Ios 通过从属性列表读取的NSDictionary进行循环会带来麻烦,ios,annotations,mkmapview,property-list,Ios,Annotations,Mkmapview,Property List,嘿,伙计们,我在读这样一篇文章: 如您所见,它是一个plist,包含不同类型的注释信息(C,Visitor)。我可以很好地显示每个注释类型,但我正在尝试循环所有类型,并在地图视图上同时显示所有注释。代码如下: NSLog(@"loadAnnotations"); NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"PermitData" ofType:@"plist"]; NSDictionary *rootOfPerm

嘿,伙计们,我在读这样一篇文章:

如您所见,它是一个plist,包含不同类型的注释信息(C,Visitor)。我可以很好地显示每个注释类型,但我正在尝试循环所有类型,并在地图视图上同时显示所有注释。代码如下:

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];
  }
 }
这是我运行程序时的控制台输出:

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";
}
因此,它正确地循环第一个NSDictionary,但在即将开始循环下一个NSDictionary时崩溃。我尝试将NSDictionary更改为NSMutableDictionary,但结果是一样的。因此,当我在表视图中选择“allallows”行时,它会挂起几分之一秒(不切换到map视图),然后崩溃,不会产生错误

如果有人不介意在这里帮助我,我将不胜感激。提前谢谢

编辑: 以下是堆栈跟踪(在下面的注释中描述):

2010-11-25 20:28:08.141停车许可证
2010-11-25 20:28:08.142停车场[39400:207]负荷注释
2010-11-25 20:28:08.142停车键:C
2010-11-25 20:28:08.143停车场[39400:207]{
纬度=“38.545301”;
经度=“-121.754066”;
副标题=“VP 17”;
title=“C停车场”;
}
2010-11-25 20:28:08.143停车场[39400:207]{
纬度=“38.544831”;
经度=“-121.754785”;
副标题=“VP 16”;
title=“C停车场”;
}
2010-11-25 20:28:08.143停车场[39400:207]{
纬度=“38.544781”;
经度=“-121.755729”;
副标题=“VP 22”;
title=“C停车场”;
}
2010-11-25 20:28:08.144停车场[39400:207]{
纬度=“38.544412”;
经度=“-121.752489”;
副标题=“VP 15”;
title=“C停车场”;
}
2010-11-25 20:28:08.145停止[39400:207]***由于未捕获的异常“NSGenericeException”而终止应用程序,原因:“***集合在枚举时发生了变异。{type=mutable dict,count=1,
条目=>
0 :  = 
}
'
***第一次抛出时调用堆栈:
(
0 CoreFoundation 0x025fdb99例外预处理+185
1 libobjc.A.dylib 0x0274d40e objc_异常_抛出+47
2 CoreFoundation 0x025fd659 uunsuFastEnumerationMutationHandler+377
3停车0x00002e93-[ParkingMapViewController加载注释]+364
4停车0x00002caf-[ParkingMapViewController viewDidLoad]+117
5 UIKit 0x0036a5ca-[UIViewController视图]+179
6 UIKit 0x003689f4-[UIViewController contentScrollView]+42
7 UIKit 0x003787e2-[UINavigationController _计算机和应用程序克隆内容插入DeltaForviewController:+48
8 UIKit 0x00376ea3-[UINavigationController\u layoutViewController:+43
9 UIKit 0x00378067-[UINavigationController\u开始转换:从ViewController:toViewController:+326
10 UIKit 0x00372ccd-[UINavigationController _STARTDEFERREEDTRANSION(如果需要)]+266
11 UIKit 0x00379d8b-[UINavigationController推送视图控制器:转换:强制立即:+876
12 UIKit 0x00372b67-[UINavigationController推送视图控制器:动画::+62
13停车0x00002914-[PermitListViewController表视图:didSelectRowAtIndexPath:+307
14 UIKit 0x00333a48-[UITableView\u selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:+1140
15 UIKit 0x0032a32e-[UITableView\u用户选择行索引路径:+219
16基金会0x000 03F21A
17 CoreFoundation 0x025def73\uuuu CFRUNLOOP\u正在调用\u OUT\u到\u计时器\u回调函数\uuuu+19
18芯基础0x025e05b4 uu CFRunLoopDoTimer+1364
19 CoreFoundation 0x0253cdd9_u CFRunLoopRun+1817
20 CoreFoundation 0x0253c350 CFRUNLOOPSCRONE+208
21 CoreFoundation 0x0253c271 CFRUNLOOPSRUNINMODE+97
22图形服务0x02edc00c GSEventRunModal+217
23图形服务0x02edc0d1 GSEventRun+115
24 UIKit 0x002ceaf2 UIApplicationMain+1160
25停车位0x00001e08主+102
26停车0x00001d99启动+53
)
在抛出“NSException”实例后调用terminate

但是,我正在for循环中释放permitdct(第二个[permitdct release]没有注释),所以我不知道为什么它会抱怨NSDictionary是不可变的。如您所见,PermitDisct的类型为NSMutableDictionary,因此我不知道它为什么会给我这个错误。

代码崩溃有两个主要原因

首先,该行位于for循环内:

[rootOfPermitDataPlistDict release];
销毁当前正在循环的对象。将其移到最末端--
if([self title]…
语句的右括号之后

第二行,这两行表示:

[permitDict release];
应删除。不要释放PermitDisct,因为您正在使用dictionaryWithDictionary创建它,该dictionaryWithDictionary返回自动删除的对象

有了这两个更改,代码应该可以运行了。
然而还有一些其他问题:

  • 您可以alloc+init
    annotationsArray
    但从不释放它(内存泄漏)。在通过该数组的for循环之后释放它(您当前有第二个
    [permitDict release];
  • 你可以使用alloc+init
    [permitDict release];
    
    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.
    }