-1

我有一个带有 UITableView 的控制器,它显示“项目”对象的列表,这些项目就像支票簿条目。除了排序之外,一切似乎都正常工作。我将在下面描述我正在寻找的排序,但目前记录是按照它们创建的顺序显示的。Item 对象 (NSManagedObjects) 的属性包括日期 (NSDate)、金额 (NSDecimalNumber) 和条目(Entry 是与 Item 有关系的 NSManaged 对象)。

在应用程序中,您创建一个具有类型(NSNumber 0 == 贷方,1 = 借方)、标题、描述等的条目。然后添加 1 个或多个具有金额、日期等的 Item 对象。

我希望在表格视图部分中按日期对项目进行分组,以便共享相同日期的所有项目都在同一部分中。在每个部分中,它们应首先按类型(先贷后借)然后按金额降序排序。在一个部分中是这样的:

2012 年 7 月 3 日

  • 学分:900
  • 借方:(25)
  • 借方:(15)

2012 年 8 月 7 日

  • 信用:1000
  • 学分:900
  • 学分:100
  • 学分:25
  • 借记:(700)
  • 借方:(450)
  • 借方:(25)

ViewController 本身是一个 UITableViewDelegate、UITableViewDataSource 和 NSFetchedResultsControllerDelegate。

这是 NSFetchedResultsController getter 方法:

- (NSFetchedResultsController *)aFetchedResultsController {

    if (_aFetchedResultsController != nil) {
        return _aFetchedResultsController;
    }

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date <= %@)", startDate, endDate];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:self.context];
    [fetchRequest setEntity:entity];
    [fetchRequest setPredicate:predicate];

    NSSortDescriptor *sortDate = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:YES];
    NSSortDescriptor *sortType = [[NSSortDescriptor alloc] initWithKey:@"entry.type" ascending:YES];
    NSSortDescriptor *sortAmount = [[NSSortDescriptor alloc] initWithKey:@"amount" ascending:NO];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDate, sortType, sortAmount, nil]];


    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController =
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                        managedObjectContext:self.context sectionNameKeyPath:@"day"
                                                   cacheName:@"Root"];
    self.aFetchedResultsController = theFetchedResultsController;
    _aFetchedResultsController.delegate = self;

    return _aFetchedResultsController;

}//end 

查看已加载:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    NSDate *today = [NSDate new];
    NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];

    [offsetComponents setMonth:-1]; //1 month ago
    startDate = [gregorian dateByAddingComponents:offsetComponents toDate:today options:0];

    [offsetComponents setMonth:1]; //1 month ahead
    endDate = [gregorian dateByAddingComponents:offsetComponents toDate:today options:0];



    //set the MOC
    self.context = [((AppDelegate *)[[UIApplication sharedApplication] delegate]) managedObjectContext];

    [self fetchRecords];

}//end viewDidLoad

以及实际获取记录的方法:

-(void)fetchRecords{

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date <= %@)", startDate, endDate];
    [[self.aFetchedResultsController fetchRequest] setPredicate:predicate];
    [NSFetchedResultsController deleteCacheWithName:@"Root"];

    NSError *error;
    if (![[self aFetchedResultsController] performFetch:&error]) {

        // Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail

    }//end if


    [_tableView reloadData];

}//end fetchRecords

"day" 是一个 Item 实例方法,我使用它让 UITableView 部分标题显示格式化的日期字符串:

- (NSString *)day {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateStyle = NSDateFormatterFullStyle;

    return [dateFormatter stringFromDate:self.date];

}//end day
4

2 回答 2

0

So as it turns out the code above all works perfectly and there really is no error with how the sorting is working. The issue is obscured by my "day" function which is making UITableView sections based on the NSDateFormatterFullStyle representation of the the item's "date" property. However the reality is that the dates are all different when it comes to the time portion which explains why they were being sorted by the order they were created.

I discovered this after trying Martin R's comment about using sectionNameKeyPath:@"date" and saw each row in its own section.

Thus the solution to my issue is to only set the month, day, and year of the "date" property when it is set, this may be unique to my application since those are the only portions of the date that I care about, not the time.

To do this I overrode the setter for "date" in my NSManagedObject "Item" with this code:

- (void)setDate:(NSDate *)date
{

    NSDateComponents *components = [[NSCalendar currentCalendar] 
                                    components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit 
                                    fromDate:date];
    NSInteger day = [components day];
    NSInteger month = [components month];
    NSInteger year = [components year];

    NSDateComponents *comps = [[NSDateComponents alloc] init];

    [comps setDay:day];
    [comps setMonth:month];
    [comps setYear:year];

    NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

    NSDate *newDate = [gregorian dateFromComponents:comps];

    [self willChangeValueForKey:@"date"];
    [self setPrimitiveValue:newDate forKey:@"date"];
    [self didChangeValueForKey:@"date"];

}//end setDate
于 2012-08-08T00:55:19.070 回答
0

从文档initWithFetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:

sectionNameKeyPath

...如果此键路径与 fetchRequest 中第一个排序描述符指定的不同,则它们必须生成相同的相对排序。

您的代码中不是这种情况。将日期转换为字符串不会保留顺序。

Apple Developer Library 中的示例代码DateSectionTitles演示了如何正确执行此操作。

于 2012-08-07T22:24:07.633 回答