在 UITableView 中对核心数据多对关系进行排序

Posted

技术标签:

【中文标题】在 UITableView 中对核心数据多对关系进行排序【英文标题】:Sorting core data to-many relationship in UITableView 【发布时间】:2013-04-04 19:25:35 【问题描述】:

我在这里看到了很多关于这个问题的帖子,但似乎没有一个可以解决我遇到的问题。

我有一个使用核心数据的应用。我正在尝试对连接到 NSFetchedResultsController 的 tableView 进行排序,使问题比这里的其他一些帖子更复杂的是我需要根据用户位置更新排序。

我的场景如下:

我有一个名为 Store 的实体。商店有很多分店,每个分店都有自己的纬度/经度。我有一个表格视图,显示所选商店的所有分支机构。我想要的是,当用户在 tableview 可见时更新他们的位置时,单元格会更新他们的位置,以便 tableview 以最近的分支在顶部进行排序。

当用户靠近分支等时,我设法让所有这些都正常工作,单元格动画上下移动。但是,我的解决方案不仅效率低下,而且当 tableview 有更多时,它还有一个主要错误单元格无法显示在屏幕上。

我知道最有可能失败的途径是使用 NSOrderedSet 对我的 Store 实体上的多对多关系进行排序。但不确定如何实现这一点,因为我正在排序的值不存储在核心数据中,而是在有意义的情况下动态计算。 lat 和 long 被存储,但距离是动态计算的,它的距离值决定了排序。

目前我使用 CLLocationManger 协议 locactionManager:didUpdateLocations 来调用 updateCellSortingOrder 这是我的排序方法。位置管理器设置为:

self.manager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;

我的排序方法有效,但就像我说的那样,它并不理想。我希望能够利用尽可能多的核心数据工具,例如 NSFetchedViewController、谓词、聚合等,而不是创建数组,对它们进行排序然后将它们推回 FRC 等,这有点像我现在正在做的......太乱了。

这是我的代码,notebranchCell 是 UITableViewCell 的子类,它有一个属性 init 来保存一个分支。 Branch 是我的实体 Branch 的一个实例

//Creating the branch cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

static NSString *CellIdentifier = @"MyTableCellView";

BranchCell *cell  = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) 
    cell = [[BranchCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];


    Branch *currentBranch =  [[self.list.listsToDelivery allObjects] objectAtIndex:indexPath.row];

    cell.branch = currentBranch;
    cell.textLabel.text = currentBranch.title;


return cell;

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations

    //update the cells
    [self updateCellSortingOrder];


- (void) updateCellSortingOrder

    // get the number of cells
    static int numberOfCells;

    numberOfCells = [[self.currentStore.branches allObjects]  count];

//loop though all the cells
    for (int cellAIndex = 0; cellAIndex < numberOfCells; cellAIndex++)

    //set up the cells
    static BranchCell * cellA;
    static BranchCell * cellB;

    //branch instances
    static Branch *branchA;
    static Branch *branchB;

    //distances
    static CLLocationDistance distanceA;
    static CLLocationDistance distanceB;
    static CLLocation *locationA;
    static CLLocation *locationB;

    //second loop to get the next cell 
    for (int cellBIndex = cellAIndex+1; cellBIndex < numberOfCells; cellBIndex++)
    
        //assign the cells
        cellA = (BranchCell *)[self.myTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:cellAIndex inSection:0]];
        cellB = (BranchCell *)[self.myTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:cellBIndex inSection:0]];

        //get the two branches which we need to compate
        branchA = cellA.branch;
        branchB = cellB.branch;

        //calculate the distance
        locationA = [[CLLocation alloc] initWithLatitude:branchA.address.region.center.latitude longitude:branchA.address.region.center.longitude];

        locationB = [[CLLocation alloc] initWithLatitude:branchB.address.region.center.latitude longitude:branchB.address.region.center.longitude];

        distanceA = [self.manager.location distanceFromLocation:locationA];
        distanceB = [self.manager.location distanceFromLocation:locationB];

        //move the cell a to cell b's location if a's distances is greater than b's
        if (distanceA > distanceB)
        
            [self.myTableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:cellAIndex inSection:0] toIndexPath:[NSIndexPath indexPathForRow:cellBIndex inSection:0]];

         
    


【问题讨论】:

【参考方案1】:

如果有人遇到与我相同的问题,这是我的解决方法。不久前修复了它,但从未更新过。它已在我的应用程序 Delivered 中使用,该应用程序现在在应用程序商店中 :)

在地图委托方法 mapView:didUpdateUserLocation 上调用 updateCellSortingOrder:

(void) updateCellSortingOrder

[self.myTableView reloadData];

[self.sortedCellArray sortUsingComparator: ^(Delivery *deliveryA, Delivery *deliveryB)

 CLLocationDistance distanceA;
 CLLocationDistance distanceB;


 distanceA = [[self.mapView userLocation] distanceFromLocation: deliveryA.address];
 distanceB = [[self.mapView userLocation] distanceFromLocation: deliveryB.address];

 if ( distanceA > distanceB)
 

     return (NSComparisonResult)NSOrderedDescending;
 

 return (NSComparisonResult)NSOrderedSame;

];

【讨论】:

以上是关于在 UITableView 中对核心数据多对关系进行排序的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 中建立多对多关系? (核心数据)

多对多关系核心数据

为多对多关系覆盖核心数据设置器方法

为核心数据手动创建多对多关系中的中间表

NSPredicate 在核心数据中的多对多关系

iphone, 以多对多关系保存数据, 核心数据