代码之家  ›  专栏  ›  技术社区  ›  Stunner

通过从属性列表中读取的nsdictionary循环,带来麻烦

  •  0
  • Stunner  · 技术社区  · 15 年前

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

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

    nslog(@“LoadAnnotations”);
    nsstring*plistpath=[[nsbundle mainbundle]pathforresource:@“permitdata”of type:@“plist”];
    nsdictionary*rootofPermitDataplistDict=[[nsdictionary alloc]initWithContentsOfFile:plistPath];
    //nsmutabledictionary*permitdict=[[nsmutabledictionary alloc]init];
    if([自标题]=@“所有许可证”)。{
    for(rootofPermitDataplistDict中的ID键){
    nslog(@“key:%@”,key);
    
    // [密钥保留];
    nsmutabledictionary*permitdict=[nsdictionary dictionary withdictionary:[rootofpermitDataplistdict objectfookey:key]];
    //[钥匙释放];
    
    //包含注释信息的数组:纬度、经度、标题、副标题(请参见permitdata.plist)
    nsarray*annotationsarray=[[nsarray alloc]initWithArray:[permitdict objectfookey:@“annotations”]];
    【许可放行】;
    [rootofPermitDataplistDict发布];
    
    cllocationCoordinate2d工作坐标;
    nsdictionary*annotationcontainerdict=[[nsdictionary alloc]init];
    //循环遍历annotations数组,创建包含plist中的信息的驻车注释
    用于(AnnotationContainerDict in AnnotationsArray){
    nslog(@“%@”,annotationContainerDict);
    
    parkingannotation*parkingannot=[[parkingannotation alloc]init];
    workingCoordinate.Latitude=[[AnnotationContainerDict Objectfookey:@“Latitude”]DoubleValue];
    workingcoordinate.longitude=[[annotationContainerDict Objectfookey:@“longitude”]doubleValue];
    [停车场设置坐标:工作坐标];
    [parkingannot settitle:[批注容器dict对象分叉:@“标题”];
    [parkinganot setsubtitle:[注释容器dict objectforkey:@“subtitle”];
    if([ParkinganNot Title]==@“C Parking”)[ParkinganNot SetAnnotationType:AnnotationTypeC];
    else if([ParkingAnnot title]==@“访客停车场”)[ParkingAnnot setAnnotationType:AnnotationTypeVisitor];
    [MapView AddAnnotation:帕金森氏病];
    [帕金森不缓解];
    }
    【许可放行】;
    }
    }
    < /代码> 
    
    

    这是我运行程序时的控制台输出:

    2010-11-25 03:25:28.020 parking[38918:207]all permits
    2010-11-25 03:25:28.021停车[38918:207]装载注释
    2010-11-25 03:25:28.021停车[38918:207]键:C
    2010-11-25 03:25:28.021停车场[38918:207]{
    纬度=“38.545301”;
    经度=“-121.754066”;
    subtitle=“副总裁17”;
    title=“C停车”;
    }
    
    
    
    
    

    property list

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

    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'
    

    2 回复  |  直到 15 年前
        1
  •  4
  •   Community Mohan Dere    9 年前

    代码崩溃有两个主要原因。

    弗斯特 ,此行位于for循环内:

    [rootOfPermitDataPlistDict release];
    

    销毁当前正在循环访问的对象。移动到最末端——在 if ([self title]... 语句。

    第二 ,这两行表示:

    [permitDict release];
    

    应该移除。不要释放permitdict,因为您正在使用返回自动释放对象的DictionaryWithDictionary创建它。

    有了这两个更改,代码就可以运行了。


    然而 ,还有一些其他问题:
    • 你分配+ init annotationsArray 但千万不要释放它(内存泄漏)。在经过该数组的for循环之后释放它(在该数组中,当前有第二个 [permitDict release]; )
    • 你分配+ init annotationContainerDict 但是,然后只将变量用作AnnotationsArray中对象的引用(因此放弃分配的内存——内存泄漏)。不要费心在annotationContainerDict上执行alloc+init,只要声明它。变化 NSDictionary *annotationContainerDict = [[NSDictionary alloc] init]; 只是 NSDictionary *annotationContainerDict; .
    • 您正在使用比较字符串 == . 使用 isEqualToString: 而是这样:
      if ([[self title] isEqualToString:@"All Permits"])... . 为了解释为什么你应该使用 isEqualToString 见 this question 和 this question .
    • 这里并不是一个很严重的问题,但是没有必要使用字典和字典,从而复制根目录中已经存在的内容。您可以使用permitdict作为对嵌入式词典的简写引用,如下所示: NSMutableDictionary *permitDict = [rootOfPermitDataPlistDict objectForKey:key]; .
    • 与annotationsarray相同:您不需要分配+init一个新数组。数组已位于rootofPermitDataplistDict中。只需这样引用: NSArray *annotationsArray = [permitDict objectForKey:@"annotations"]; . 如果您决定这样做,请不要发布注释。

    这个 Memory Management Programming Guide 详细解释了这一切。

        2
  •  1
  •   NSGod Luchian Grigore    15 年前

    首先,您的代码有很多问题,但是除非这是性能关键的代码,否则您将每秒循环数百次(可能会创建许多自动释放的对象),使用alloc]init]方法只会使代码更难执行。(因为你必须在精神上经历并不断地平衡一个分配与一个释放)。别误会我,重要的是你要理解保留和释放等,但这是我解决问题的方法。

    记住你在控制之中。使您的停车注释类能够“独立思考”一点。在下面的示例中,我添加了一个-(ID)initWithDictionary:这样您的另一个类就不必坐在那里一个接一个地设置键了。(有一些虚构的部分,我假设你会填补空白…

    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.
    }
    
    推荐文章