簡體   English   中英

使用NSPredicate過濾包含帶有NSDate字段的對象的NSArray

[英]Filtering a NSArray containing objects with a NSDate field with NSPredicate

我有一個對象數組,每個對象都包含一個稱為date的字段。 我想使用NSPredicate創建此數組的一個子集,在這里我只拉出屬於某個日期范圍內的那些對象。 這是我正在使用的代碼:

predicate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date =< %@)", startDate, endDate];
_daysArray = [_cachedDaysArray filteredArrayUsingPredicate:predicate];

我遇到的問題是startDateendDate是同一天,但時間不同。 這是XCode調試器中的變量視圖

在此處輸入圖片說明

如您所見,我在數組中有一個對象,該對象的date字段等於startDate ,但是您還可以看到_daysArray在執行過濾器后不包含任何元素。

當日期不是同一天時,這很好用。

任何幫助將不勝感激。

編輯#1

這是評論者要求的predicate變量的po

(lldb) po predicate
date >= CAST(406616400.676014, "NSDate") AND date <= CAST(406702799.677098, "NSDate")
(lldb)

編輯#2

(lldb) po [[_cachedDaysArray firstObject] date]
2013-11-18 05:00:00 +0000
(lldb) 

編輯#3

Martin R.通過對startDate計算方式的評論使我走上了正確的道路。 現在,我已經更改了它,它正在工作。 我正在使用一種方法來計算startDate 以前,我使用NSUIntegerMax指示組件,現在我專門將它們分解:

-(NSDate *)pastDate:(NSInteger)daysPast
{
    // Get the appropriate calendar
    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSDateComponents *startComponents = [calendar components:(NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitYear|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond) fromDate:[NSDate date]];
    [startComponents setHour: 00];
    [startComponents setMinute: 00];
    [startComponents setSecond: 00];
    startComponents.day = startComponents.day - daysPast;

    return [calendar dateFromComponents:startComponents];
}

從謂詞的輸出

date >= CAST(406616400.676014, "NSDate") AND date <= CAST(406702799.677098, "NSDate")

可以看到startDate 並非完全是“ 2013-11-20 05:00:00 +0000”(UTC)或“ 2013-11-20 00:00:00”(EST),而是0.676014秒后 因此,如果_cachedDaysArray對象的日期恰好位於2013-11-20的午夜,則它與謂詞匹配。

似乎startDateendDate的計算與您期望的不完全相同。

在將日期傳遞給謂詞之前,應將日期轉換為不包括時間。 嘗試這個:

-(NSDate*)dateNoTime:(NSDate*)myDate
{

NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate: myDate];
return [[NSCalendar currentCalendar] dateFromComponents:comp];

}

嘗試這個:

predicate =[NSPredicate predicateWithBlock:^BOOL(TRDay *evaluatedObject, NSDictionary *bindings) {
    return evaluatedObject.date.timeIntervalSince1970 >= startDate.timeIntervalSince1970 && evaluatedObject.date.timeIntervalSince1970 <= endDate.timeIntervalSince1970;
}];

我嘗試過這樣的事情:

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

NSDateComponents *components3 = [[NSDateComponents alloc] init];
[components3 setYear:2013];
[components3 setMonth:11];
[components3 setDay:20];
NSDate *startDate = [gregorianCalendar dateFromComponents:components3];

[components3 setHour:23];
[components3 setMinute:59];
[components3 setSecond:59];

NSDate *endDate = [gregorianCalendar dateFromComponents:components3];
[gregorianCalendar release];

NSDictionary* dict = [NSDictionary dictionaryWithObjects:@[startDate] forKeys:@[@"date"]];
NSArray* mainArray = [NSArray arrayWithObjects:dict, nil];

NSPredicate* pred = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date =< %@)", startDate, endDate];
NSArray* filteredArray = [mainArray filteredArrayUsingPredicate:pred];

它按預期工作。 基本上,這意味着您在其他地方有錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM