使用numberOfSectionsInTableView中的NSFetchedResultsController对日期进行分组

时间:2014-03-26 18:53:09

标签: ios objective-c uitableview nsfetchedresultscontroller

我有UITableViewController使用NSFetchedResultsController显示列表。 这是myObject的列表,并具有属性date

我创建了一个方法- (NSFetchedResultsController *)fetchedResultsController来获取按日期排序的所有条目。

结果如下: enter image description here

在此之后我添加了- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section,以便时间+日期显示在dateStyle:NSDateFormatterMediumStyle中。

如下图所示,您可以看到日期打印正确,但2014年3月12日的2行和2014年3月14日的其他2行未组合在一起。

enter image description here

我的猜测是我需要更改numberOfSectionsInTableView方法,因为它仍在查看日期+时间,而不仅仅是日期,但我不知道如何。

我的代码:

   - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        NSInteger count = [[self.fetchedResultsController sections] count];
        return count;
    }

一种可能性是在我的对象中添加一个属性,例如“sectionIdentifier”'仅存储日期并使用它。我想知道是否有人知道如何处理这个问题。是否可以将这些日期组合在一起,我将代码添加到- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

3 个答案:

答案 0 :(得分:2)

在Swift 4.2中得出答案。

有两个步骤:

步骤1:在extension上创建NSManagedObject(示例使用Entry作为托管对象),并使用@objc公开它:

extension Entry {
    @objc var isoDate: String { get {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        // insert settings for TimeZone and Calendar here
        return formatter.string(from: Entry.date!)
    }}
}

步骤2:使用属性isoDate作为sectionNameKeyPath的值:

let fetchedResultController = NSFetchedResultsController(fetchRequest: expenseFetchRequest(),
                                                             managedObjectContext: coreDataStack.mainContext,
                                                             sectionNameKeyPath: #keyPath(Expense.dateISO),
                                                             cacheName: nil)

现在,您的FRC应该可以将对象分成几部分了!

答案 1 :(得分:1)

我喜欢用FRC控制它,如果想要不同/自定义功能,请保留委托调用来更改它。我还认为FRC通常应该被构建为被观察实体的类方法。

您可以使格式化的字符串成为对象的完整属性,但这似乎很浪费。

你也可以使它成为一个真正的瞬态属性。这可能更合适,但我使用的是现有模型,并且不想更改模型。自那个项目以来,我对其他任何类似的案例都采用了这种方法。

无论如何,这个例子几乎都是从现有应用程序中直接获取的。我不得不改变一些事情,所以我希望我没有遗漏任何东西。

创建FRC使用的获取请求,以便根据对象的date属性进行排序。这允许在标准属性上获取正常的核心数据。

+ (NSFetchedResultsController *)
    fetchedResultsController:(NSManagedObjectContext *)context
{
    NSFetchRequest* request = [NSFetchRequest
        fetchRequestWithEntityName:[self entityName]];
    request.sortDescriptors = @[[NSSortDescriptor
        sortDescriptorWithKey:@"date"
                    ascending:YES]];
    request.fetchBatchSize = 30;
    request.returnsObjectsAsFaults = NO;

    NSString *cacheName = [[self entityName]
        stringByAppendingString:@"-all-bydate"];
    return [[NSFetchedResultsController alloc]
        initWithFetchRequest:request
        managedObjectContext:context
          sectionNameKeyPath:@"dateAsSectionName"
                   cacheName:cacheName];
}

将一个实例变量添加到您的子类......您将自己管理它......

@implementation MyManagedObjectSubclass {
    NSString *dateAsSectionName_;
}

添加访问者方法。我们只创建一次格式化程序。根据自己的喜好改变它。

- (NSString*)dateAsSectionName
{
    static NSDateFormatter *dateFormatter;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        dateFormatter = [[NSDateFormatter alloc] init];
        dateFormatter.dateFormat = @"EEE, MMM d, h:mm a";
        dateFormatter.dateFormat = @"EEEE MMMM d";
    });

    if (dateAsSectionName_ == nil) {
        NSDate *date = [self primitiveDate];
        dateAsSectionName_ = [dateFormatter stringFromDate:date];
    }
    return dateAsSectionName_;
}

当日期更改时清除我们的部分名称,因此我们将在下次调用访问者时重新计算其值。

- (void)setDate:(NSDate*)date
{
    if ([[self primitiveDate] isEqualToDate:date]) return;

    [self willChangeValueForKey:@"date"];
    [self setPrimitiveDate:date];
    [self didChangeValueForKey:@"date"];

    dateAsSectionName_ = nil;
}

告诉KVO dateAsSectionName取决于date

+ (NSSet *)keyPathsForValuesAffectingDateAsSectionName
{
    return [NSSet setWithObject:@"date"];
}

答案 2 :(得分:0)

阅读这两篇文章,添加属性似乎就是答案