排序/过滤 NSFetchRequest 如何编写将使用当前日期的排序描述符?

Posted

技术标签:

【中文标题】排序/过滤 NSFetchRequest 如何编写将使用当前日期的排序描述符?【英文标题】:Sort/Filter NSFetchRequest how to write sort descriptor taht will use current date? 【发布时间】:2014-06-09 09:07:11 【问题描述】:

我存储在Core Data 2 个日期属性中,一个是过期日期,第二个是“琥珀”日期(过期日期前 X 周的日期)。我想按以下方式对结果进行排序:

琥珀色日期之前的项目 - (绿色)现在 琥珀色日期之后但过期日期之前的项目 - (琥珀色)琥珀色 过期日期或之后的商品 -(红色)过期

你能帮我解决这个问题吗?

更新 经过更多研究,我发现我可以获取未排序的结果,将其放入数组中并对数组进行排序,并且表将使用该数组作为数据源 - 改变太多以使其在我的应用程序中工作。 也有可能使用额外的参数,它将根据上面的列表保存评估值。然后提取需要 2 个步骤:

    获取数据并对每个项目运行评估 按此获取排序数据 评估属性

后一种解决方案是我最好的选择,所以有人可以帮我解决这个问题吗?

编辑

state 属性定义为int16_t

@property (nonatomic, assign) int16_t state;

在带有表格的视图的viewDidLoad 中,我在获取排序结果之前调用了fallowing:

 NSFetchRequest *fetchRequest = 
[NSFetchRequest fetchRequestWithEntityName:@"MyTable"];
    NSSortDescriptor *sortTitle = 
    [NSSortDescriptor sortDescriptorWithKey:@"name"
                                  ascending:YES];
    [fetchRequest setSortDescriptors:@[sortByTitle]];

    NSFetchedResultsController *ctrl = [[NSFetchedResultsController alloc]
                initWithFetchRequest:fetchRequest
                managedObjectContext:[NSManagedObjectContext defaultContext]
                  sectionNameKeyPath:nil
                           cacheName:nil];

    NSError* fetchError = nil;
    if([ctrl performFetch:&fetchError] == NO) 

        NSLog(@"Error: perform fetch failed, %@",[fetchError description]);

     else 
        //do we have results here?
        id <NSFetchedResultsSectionInfo> sectionInfo = 
                                      [ctrl.sections objectAtIndex:0];
        NSArray * items = [sectionInfo objects];
        for (int i=0; i<items.count; i++) 
            CourseCD* item = items[i];
            NSLog(@"%d - %@",i,item);
            [item evaluateState];//category adds this method
        
    

这是类别中的方法

-(State) evaluateState 
    CourseComplianceState pState = StateUnknown;
    if (self.expire == nil) 
        [self setState:pState];
        return pState;
    

    NSDate* now = [[NSDate alloc] init];
    pState = StateNotExpired;

    if ([NSDate isDate:now inRangeFirstDate:self.thresholdDate 
              lastDate:self.expireDate]) 
        //amber
        pState = StateWithinThreshold;
     else if ([NSDate isDate:now inRangeFirstDate:self.expireDate 
                     lastDate:[NSDate distantFuture]])
        //expired
        pState = StateExpired;
    

    //
    [self setState:pState];

    NSLog(@" - evaluateState -");

    return pState;

这是状态结构

enum 
    StateUnknown,
    StateNotExpired,
    StateWithinThreshold,
    StateExpired

;
typedef int16_t State;

然后在此调用之后,我使用具有以下排序的目标调用,并且我正在使用与表一起使用的控制器。

//later I use following sort descriptors
NSSortDescriptor *sortState = [NSSortDescriptor 
                                  sortDescriptorWithKey:@"state"
                                              ascending:YES];
NSSortDescriptor *sortExpire = [NSSortDescriptor 
                                  sortDescriptorWithKey:@"expire"
                                              ascending:YES];

编辑

NSSortDescriptor *sortByTitle = [NSSortDescriptor 
                                   sortDescriptorWithKey:@"name" 
                                               ascending:YES];
NSFetchRequest *fetchRequest = [NSFetchRequest 
                                 fetchRequestWithEntityName:@"Course"];
[fetchRequest setSortDescriptors:@[sortState,sortExpire,sortByTitle]];


self.resultsController = [[NSFetchedResultsController alloc] 
                           initWithFetchRequest:fetchRequest
                   managedObjectContext:[NSManagedObjectContext defaultContext]
                             sectionNameKeyPath:nil
                                      cacheName:nil];

self.resultsController.delegate = self;

NSError* fetchError = nil;
if([self.resultsController performFetch:&fetchError] == NO) 

    NSLog(@"Error: perform fetch failed, %@",[fetchError description]);


但它仅按过期日期排序,第一次评估运行忽略或不保存状态。

编辑 2014/06/10

这是 NSManagedObject 类中的设置器

//.h
@property (nonatomic, assign) int16_t state;

//.m
@synthesize state=_state;
-(void) setState:(int16_t)state 
    _state = state;

    NSError* error = nil;
    [[NSManagedObjectContext defaultContext] save:&error];
    if(error != nil)
        NSLog(@"Error in setState, details:%@",[error description]);
    

最终编辑 - 已解决

决议是: 删除 @synthesise state = _state;-(void) setState:(int16_t)state 并离开 @dynamic state。然后在 evaluateState 而不是 [self setState:pState]; 我使用 self.state=pState; 现在它按要求排序。现在的问题是为什么合成属性不起作用?

【问题讨论】:

我会将评估作为一个单独的操作运行(在使用 NSFetchRequest 获取的项目上)并让 FRC 仅处理 UI,在纸面上您使用更多资源,但它允许您在 FRC 使用批次来补偿为了它。但是是的 - 在同步调用 performFetch: 之后,您可以访问获取的项目,因此如果这些部分没有按照您预期的方式构建,您应该检查评估代码。 评估似乎有效,唯一的问题是它不适用于排序:) 所以状态在单元格中使用并正确显示(如预期的那样)评估状态,但它没有像我一样排序认为它应该被排序:) setState 当从evaluteState 调用时调用 save 所以它应该被存储但它不是所以也许这就是问题吗?无论如何,您能否在答案中详细说明您的解决方案并尽可能详细:) 因为对我来说,objective-c 仍然是新的 所以问题是您无法读取修改后的属性?那很奇怪。我了解您的代码,因为evaluateState 属于实体类类别,如果是,请分享设置器代码,我想您一定是在使用一些棘手的东西,例如关联对象。 我已经更新了问题 我明白了,你需要刷新那些属性被这个setter改变的对象,尝试使用NSManagedObjectContext -refreshObject:mergeChanges: 【参考方案1】:

解决方案是:删除@synthesise state = _state;-(void) setState:(int16_t)state 并保留@dynamic 状态。然后在 evaluateState 而不是 [self setState:pState]; 我使用 self.state=pState; 现在它按要求排序。

【讨论】:

以上是关于排序/过滤 NSFetchRequest 如何编写将使用当前日期的排序描述符?的主要内容,如果未能解决你的问题,请参考以下文章

嵌套 NSFetchRequest?

ios: NSFetchRequest 和过滤

核心数据 NSFetchRequest 按类别排序方法返回值

按计算结果排序 NSFetchRequest

iOS - NSFetchRequest:对字符串长度进行排序

根据实体类对 NSFetchRequest 进行排序