【问题标题】:NSFetchedResultsController section ordering using display orderNSFetchedResultsController 部分使用显示顺序排序
【发布时间】:2011-05-22 01:12:51
【问题描述】:

我目前有一个选项允许用户在我的 iPhone 应用程序中更改类别的显示顺序。

我想使用 NSFetchedResultsController 对表视图进行分区,以便分区标题是按“category.displayOrder”排序的“category.name”,其中“category”与我正在获取的实体具有一对一的关系。使切片正常工作的唯一方法是使用“category.displayOrder”作为部分标题。

NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"category.displayOrder" ascending:YES];
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];

NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, sortDescriptor2, nil];

[fetchRequest setSortDescriptors:sortDescriptors];

[fetchRequest setFetchBatchSize:10];

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                                                                    managedObjectContext:managedObjectContext
                                                                                                      sectionNameKeyPath:@"category.name"
                                                                                                               cacheName:nil];

关于如何将部分标题命名为不同于我正在排序的属性的任何想法?

【问题讨论】:

    标签: ios core-data nsfetchedresultscontroller


    【解决方案1】:

    不确定我是否完全理解你的问题,但我在我的应用程序中做了类似的事情,这是我如何让它工作的:

    首先是 fetchedResultsController 方法,在这里我根据我想要做的事情来设置排序描述和谓词。在这种情况下,我想按发行日期对电影标题进行排序,然后按名称排序。然后用我的谓词抓取特定“类型”和某个“发布日期”范围内的实体。

    在我的 fetchresultscontroller 定义中,您将 sectionNameKeyPath 设置为“releaseDate”,因此我的部分标题将基于日期。

    - (NSFetchedResultsController *)fetchedResultsController {
    
        if (fetchedResultsController_ != nil) {
            return fetchedResultsController_;
        }
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSSortDescriptor *sortByReleaseDate = [[NSSortDescriptor alloc] initWithKey:@"releaseDate" ascending:NO];
        NSSortDescriptor *sortByName = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
        NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortByReleaseDate,sortByName, nil];
        [fetchRequest setSortDescriptors:sortDescriptors];
        [sortDescriptors release];
        [sortByName release];
        [sortByReleaseDate release];            
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(type == 'Movies') AND (releaseDate <= %@) AND (releaseDate >= %@)", [NSDate date], [NSDate dateWithTimeIntervalSinceNow:kOneDayTimeInterval*-30]];
        [fetchRequest setPredicate:predicate];
    
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Movie" inManagedObjectContext:self.managedObjectContext];
            [fetchRequest setEntity:entity];
    
        NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"releaseDate" cacheName:nil];
    
        ...// Perform and return fetch here, error handling etc...
    
        return fetchedResultsController_;
    
    }    
    

    然后在我的表格视图数据源委托方法中,在将我的 NSDate 转换为 NSString 之后,我返回每个标题的实际标题(请记住,您必须为表格视图标题标题返回 NSString。

    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    
        NSString *rawDateStr = [[[self.fetchedResultsController sections] objectAtIndex:section] name];
        //convert default date string to NSDate...
        NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
        [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss ZZ"];
        NSDate *date = [formatter dateFromString:rawDateStr];
    
        //convert NSDate to format we want...
        [formatter setDateFormat:@"d MMMM yyyy"];
        NSString *formattedDateStr = [formatter stringFromDate:date];
        return formattedDateStr;
    
    }
    

    因此,如果我想更改数据的显示方式,例如按 titleName 组织,我会将 fetchedResultsController 对象更改为:

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"titleName" cacheName:nil];
    

    并修改我的 tableview:titleForHeaderInSection: 数据源方法以简单地返回 titleName(这已经是一个字符串):

     - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    
            return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
    }
    

    我希望这可以帮助您找到特定问题的解决方案。

    干杯, 罗格

    【讨论】:

    • 我正在尝试按 displayOrder (NSInteger) 对我的部分进行排序,但我不想将整数显示为部分标题,而是显示与该 displayOrder 对应的名称。因此,我将使用“FirstName”、“Second Name”和“Third Name”来代替章节标题 1、2 和 3。你认为最好的方法是根据titleForHeaderInSection中的显示顺序来确定标题吗?
    • 据我所知,这是唯一的方法。您可以在 displayOrder 上进行切换,然后返回您想要显示的相应部分。
    • 我希望不必在 titleForHeaderInSection 中执行另一次提取,但似乎没有其他方法......
    【解决方案2】:

    我遇到了同样的问题,我有另一个解决方案 - 为 sectionNameKeyPath 使用瞬态属性,即 category.sectionName。似乎如果您将核心数据属性用作 sectionNameKeyPath ,它将尝试使用该属性进行排序。

    所以使用上面的示例:

    NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"category.displayOrder" ascending:YES];
    NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, sortDescriptor2, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];
    
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"category.sectionName" cacheName:nil];
    

    类别.h:

    @interface Category : NSManagedObject
    
    @property (nonatomic, retain) NSString* name;
    @property (nonatomic, retain) NSNumber* displayOrder;
    
    -(NSString*) sectionName;
    
    @end
    

    类别.m:

    @implementation Category
    
    @dynamic name;
    @dynamic displayOrder;
    
    -(NSString*) sectionName{
        return self.name;
    }
    
    @end
    

    然后在你的视图控制器中:

    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
        id<NSFetchedResultsSectionInfo> sectionInfo=[self.resultsController.sections objectAtIndex:section];
        return sectionInfo.name;
    }
    

    【讨论】:

      【解决方案3】:

      感谢 Rog,我能够解决这个问题并提出解决方案。它没有我想要的那么干净,所以如果有人有更好的方法,我很想听听。

      根据我所学到的(我可能是错的,请告诉我),您只能通过您订购表的属性来命名部分 (sectionNameKeyPath)。就我而言,我想使用名为 displayOrder 的属性对表进行排序,但我不希望我的部分标题为 0、1、2 等。相反,我希望部分标题使用标题属性“Name1”,对应于displayOrder的“Name2”等。为此,我根据 titleForHeaderInSection 中的 displayOrder 确定标题标题:

              NSString *displayOrder = [sectionInfo name];
      
              NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
              [fetchRequest setEntity:[NSEntityDescription entityForName:@"Platform" inManagedObjectContext:managedObjectContext]];
      
              NSNumberFormatter * numberFormatter = [[NSNumberFormatter alloc] init];
              [numberFormatter setNumberStyle:NSNumberFormatterNoStyle];
      
              NSPredicate *predicate = [NSPredicate predicateWithFormat:@"displayOrder == %@", [numberFormatter numberFromString:displayOrder]];
              [fetchRequest setPredicate:predicate];
      
              Platform *platform;
              NSError *error = nil;
              NSArray *fetchResults = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
              if ([fetchResults count] > 0) {
                  platform = [fetchResults objectAtIndex:0];
                  headerView.titleLabel.text = [platform name];
              } else {
                  headerView.titleLabel.text = @"Unknown";
              }
      
              [numberFormatter release];
              [fetchRequest release];
      

      谢谢罗格!

      【讨论】:

      • 不用担心,我很高兴它有帮助!
      • @avenged,你到底是怎么发现的? “根据我所学到的(我可能错了,请告诉我),您只能通过您订购餐桌的属性来命名部分(sectionNameKeyPath)。”那是要了我的命!谢谢!
      【解决方案4】:

      就我而言,我必须使用 RTFM:

      - initWithFetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:

      如果这个 sectionNameKeyPath 与 fetchRequest 中的 first sort descriptor 指定的不同,它们必须生成相同的相对顺序。例如, fetchRequest 中的第一个排序描述符可能指定持久属性的键; sectionNameKeyPath 可能为从持久属性派生的瞬态属性指定一个键。

      当托管对象的sectionNameKeyPath 或NSSortDescriptor 属性更改为与其他属性不同的排序顺序时,这会导致表视图排序不一致。

      来源:
      https://richardwarrender.com/2010/10/core-data-objects-in-wrong-sections/

      【讨论】:

        猜你喜欢
        • 2012-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-18
        • 2013-07-16
        • 1970-01-01
        • 2014-03-04
        • 1970-01-01
        相关资源
        最近更新 更多