ios - NSMutableArray 数据按距离排序

标签 ios objective-c nsmutablearray

我的 MutableArray 有问题。我的 TableView 中有数据数组,一切正常,但是当数据按距离排序并且我在单元格中选择一个项目时,它会在新的 View Controller 中显示不正确的数据。它显示没有排序的数据。这就像一个断开的链接)希望得到你的帮助)

我是 obj-c 的新手,所以我很抱歉)

这是我的代码:

       list = [[NSMutableArray alloc] init];

        [list addObject:@{@"name": @"Central office", @"address":@"наб. Обводного канала, д.66А", @"phone":@"+7 (812) 320-56-21 (многоканальный)", @"workTime":@"ПН-ПТ: с 9:30 до 18:30", @"email":@"mail@ibins.ru", @"payment":@"Принимаются к оплате пластиковые карты VISA и MasterCard", @"longitude":@30.336842, @"latitude":@59.913950}];

        [list addObject:@{@"name": @"Second office", @"address":@"ул. Камышовая, д.38", @"phone":@"+7 (812) 992-992-6; +7 (812) 456-26-43", @"workTime":@"Ежедневно: с 9:30 до 20:00", @"email":@"sever@ibins.ru", @"payment":@"Принимаются к оплате пластиковые карты VISA и MasterCard", @"longitude":@30.219863, @"latitude":@60.008805}];

        [list addObject:@{@"name": @"Third office", @"address":@"Street name", @"phone":@"phone number", @"workTime":@"Work time", @"email":@"email address", @"longitude":@30.294254, @"latitude":@60.028728}]; 

    [self constructList];
    [self constructPins];
    }



- (IBAction)switchDisplayType:(id)sender {
    [UIView beginAnimations:@"View Flip" context:nil];
    [UIView setAnimationDuration:0.80];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];
    [UIView commitAnimations];

    if ([(UISegmentedControl*)sender selectedSegmentIndex] == 1) {
        map.hidden = YES;
        contentSV.hidden = NO;
    }
    else {
        map.hidden = NO;
        contentSV.hidden = YES;
    }
}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
    static NSString* BridgeAnnotationIdentifier = @"bridgeAnnotationIdentifier";

    MKPinAnnotationView* customPinView = [[[MKPinAnnotationView alloc]
                                           initWithAnnotation:annotation reuseIdentifier:BridgeAnnotationIdentifier] autorelease];
    customPinView.pinColor = MKPinAnnotationColorRed;
    customPinView.animatesDrop = YES;
    customPinView.canShowCallout = YES;

    UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
   // NSLog(@"%@",rightButton);
    [rightButton addTarget:self
                    action:@selector(annotationButtonTapped:)
          forControlEvents:UIControlEventTouchUpInside];
    customPinView.rightCalloutAccessoryView = rightButton;
    return customPinView;//[kml viewForAnnotation:annotation];
}

- (void)annotationButtonTapped:(id)sender {
    DetailVC *sampleVC = [[DetailVC alloc] initWithNibName:@"DetailVC" bundle:[NSBundle mainBundle]];
    [self.navigationController pushViewController:sampleVC animated:YES];
    [sampleVC release];

    for (NSDictionary *dict in list) {
        if ([[dict valueForKey:@"name"] isEqualToString:selectedAnnTitle]) {
            [sampleVC updateViewWithDict:dict];
        }
    }
}



- (void)constructPins {
    for (NSDictionary *dict in list) {
        MKCoordinateRegion region;
        MKCoordinateSpan span;
        span.latitudeDelta = 0.3;
        span.longitudeDelta = 0.3;

        CLLocationCoordinate2D location;

        location.latitude = [[dict valueForKey:@"latitude"] floatValue];
        location.longitude = [[dict valueForKey:@"longitude"] floatValue];

        if (location.latitude == 0.0 && location.longitude == 0.0)
            return;

        region.span = span;
        region.center = location;

        MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
        point.coordinate = location;
        point.title = [dict valueForKey:@"name"];

        [map addAnnotation:point];
        [map setRegion:region animated:YES];
    }
}

- (void)constructList {
    int n = 0;
    for (NSDictionary *dict in list) {
        UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 100*n, 320, 100)];
        container.backgroundColor = [UIColor whiteColor];

        UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 320, 100)];
        button.tag = n;
        [button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
        [container addSubview:button];


        NSString *str = [NSString stringWithFormat:@"%@\nAddress: %@\nPhone: %@\nWork Time: %@", [dict valueForKey:@"name"], [dict valueForKey:@"address"], [dict valueForKey:@"phone"], [dict valueForKey:@"workTime"]];
        UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 300, 80)];
        nameLabel.textAlignment = NSTextAlignmentLeft;
        nameLabel.numberOfLines = 0;
        nameLabel.text = str;
        nameLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:12.0];
        [container addSubview:nameLabel];


        UIView *separator = [[UIView alloc]initWithFrame:CGRectMake(0, 99, 320, 1)];
        separator.backgroundColor = [UIColor darkGrayColor];
        [container addSubview:separator];


        [contentSV addSubview:container];


        n++;
        contentSV.contentSize = CGSizeMake(0, 100*n);
    }
}

- (float)distanceBetweenLat1:(float)tlat1 lon1:(float)tlon1 lat2:(float)tlat2 lon2:(float)tlon2 {
    float result = 0.0;
    int R = 6371;

    float currentLatitude = tlat1;
    float currentLongtitude = tlon1;

    float lat2 = tlat2;
    float lon2 = tlon2;

    float dLat = (lat2-currentLatitude)*M_PI/180;
    float dLon = (lon2-currentLongtitude)*M_PI/180;
    float nlLat = currentLatitude*M_PI/180;
    lat2 = lat2*M_PI/180;

    float a = sin(dLat/2) * sin(dLat/2) +  sin(dLon/2) * sin(dLon/2) * cos(nlLat) * cos(lat2);
    float c = 2 * atan2(sqrt(a), sqrt(1-a));
    result = R * c;

    return result;
}

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
    selectedAnnTitle = [view.annotation title];

    return;

    DetailVC *sampleVC = [[DetailVC alloc] initWithNibName:@"DetailVC" bundle:[NSBundle mainBundle]];
    [self.navigationController pushViewController:sampleVC animated:YES];


    NSString *ttl = [view.annotation title];

    for (NSDictionary *dict in list) {
        if ([[dict valueForKey:@"name"] isEqualToString:ttl]) {
            [sampleVC updateViewWithDict:dict];
        }
    }

    [map deselectAnnotation:view.annotation animated:NO];
}

- (void)buttonTapped:(id)sender {
    DetailVC *sampleVC = [[DetailVC alloc] initWithNibName:@"DetailVC" bundle:[NSBundle mainBundle]];
    [self.navigationController pushViewController:sampleVC animated:YES];


    int n = 0;
    for (NSDictionary *dict in list) {
        if (n == [sender tag]) {
            [sampleVC updateViewWithDict:dict];
        }
        n++;
    }
}

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
    NSLog(@"didUpdateUserLocation");

    MKAnnotationView* annotationView = [mapView viewForAnnotation:userLocation];
    annotationView.canShowCallout = NO;

    if (!userLocationUpdated) {
        if (userLocation.coordinate.latitude > 0.1 && userLocation.coordinate.longitude > 0.1) {
         //   NSLog(@"SORT BY DISTANCE");

            userLocationUpdated = YES;

            for (int i = 0; i < [list count]; i++) {
                NSMutableDictionary *record = [[NSMutableDictionary alloc] initWithDictionary:[list objectAtIndex:i]];

                float latitude = [[record valueForKey:@"latitude"] floatValue];
                float longitude = [[record valueForKey:@"longitude"] floatValue];

                float dist = [self distanceBetweenLat1:map.userLocation.coordinate.latitude lon1:map.userLocation.coordinate.longitude lat2:latitude lon2:longitude];
                NSNumber *distN = [NSNumber numberWithFloat:dist];
                [record setObject:distN forKey:@"distance"];

              [list replaceObjectAtIndex:i withObject:record];
            }

            NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"distance" ascending:YES];
            NSArray *itemsListSorted = [[NSArray alloc] initWithArray:list];
            itemsListSorted = [itemsListSorted sortedArrayUsingDescriptors:[NSArray arrayWithObjects:descriptor,nil]];

            for (UIView *view in contentSV.subviews) {
                [view removeFromSuperview];
            }

            for (int i = 0; i < [itemsListSorted count]; i++) {
                UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 100*i, 320, 100)];
                container.backgroundColor = [UIColor whiteColor];

                UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 320, 100)];
                button.tag = i;
                [button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
                [container addSubview:button];


                NSString *str = [NSString stringWithFormat:@"%@\nAddress: %@\nPhone: %@\nWorkTime: %@", [[itemsListSorted objectAtIndex:i] valueForKey:@"name"], [[itemsListSorted objectAtIndex:i] valueForKey:@"address"], [[itemsListSorted objectAtIndex:i] valueForKey:@"phone"], [[itemsListSorted objectAtIndex:i] valueForKey:@"workTime"]];
                UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 300, 80)];
                nameLabel.textAlignment = NSTextAlignmentLeft;
                nameLabel.numberOfLines = 0;
                nameLabel.text = str;
                nameLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:12.0];
                [container addSubview:nameLabel];


                UILabel *distanceLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 2, 300, 21)];
                distanceLabel.textAlignment = NSTextAlignmentRight;
                distanceLabel.text = [NSString stringWithFormat:@"%.1f км", [[[itemsListSorted objectAtIndex:i] valueForKey:@"distance"] floatValue]];
                distanceLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:12.0];
                distanceLabel.textColor = [UIColor lightGrayColor];
                [container addSubview:distanceLabel];


                UIView *separator = [[UIView alloc]initWithFrame:CGRectMake(0, 99, 320, 1)];
                separator.backgroundColor = [UIColor darkGrayColor];
                [container addSubview:separator];


                [contentSV addSubview:container];


                contentSV.contentSize = CGSizeMake(0, 100*(i+1));
            }
        }
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end

最佳答案

虽然此代码存在许多问题(其中最少的是距离计算的一些小精度问题),问题不在于距离计算

详细 View Controller 显示不正确的数据,因为它从 list 数组中获得数据,该数组不是本身按距离排序。

didUpdateUserLocation 委托(delegate)方法中,list 的内容被复制到名为 itemsListSorted本地数组。

只有 itemsListSorted 数组按距离排序,然后使用此本地 数组更新显示。

但原始的 list 数组(buttonTapped 方法将其用作发送到详细 View Controller 的数据源)从不 已更新。

因此,如果“Central Office”位于 list 中的索引 0,但在 itemsListSorted 中移动到索引 2,则显示会显示正确的位置,但是当您点击它时,buttonTapped 方法从 list 数组发送索引 2 处的项目,该数组有“Central Office”(它仍然在索引 0 列表).


解决此问题的一种方法是停止使用本地数组并直接对 list 数组进行排序。

didUpdateUserLocation 中,您可以替换这两行:

NSArray *itemsListSorted = [[NSArray alloc] initWithArray:list];
itemsListSorted = [itemsListSorted sortedArrayUsingDescriptors:[NSArray arrayWithObjects:descriptor,nil]];

用这个:

[list sortUsingDescriptors:[NSArray arrayWithObjects:descriptor,nil]];

然后用 list 替换所有对 itemsListSorted 的引用。



关于代码的其他问题,没有足够的空间将它们全部指出或在一个答案中解释它们。然而,这里只是一些亮点:

  • 不要手动创建“表格 View ”,而是使用实际的 UITableView
  • 不要手动计算坐标之间的距离,而是使用 CLLocation 类中的 distanceFromLocation 方法 MKMetersBetweenMapPoints功能。
  • viewForAnnotation 中,如果 annotationMKUserLocation 类型,您应该返回 nil 否则它将显示为红色别针和其他别针一样。
  • 使用 ARC 而不是手动内存管理。

关于ios - NSMutableArray 数据按距离排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22901040/

相关文章:

ios - 如何测试 iOS 应用程序的 facebook 见解?

ios - 如何将json字符串转换为元素数组?

ios - 更新到 Swift 3 后的问题

ios - 在iOS聊天中像Facebook一样发表评论

IOS - 显示远程图像缩略图

iphone - 使用 NSUserDefaults 保存游戏设置/状态的优点?

ios - 从核心数据中过滤标题

iOS聊天应用程序设计

ios - 数组不在 View Controller ios 之间传递

ios - 全局变量在不存在时被识别为 null - Objective C