【问题标题】:Use UISearchBar to search NSDates (which are strings using NSDateFormatter) in Core Data使用 UISearchBar 在 Core Data 中搜索 NSDates(使用 NSDateFormatter 的字符串)
【发布时间】:2013-12-09 18:57:45
【问题描述】:

我有一个表格视图,它目前正在完美地搜索核心数据数据库的字符串属性。但是,它不是搜索日期。

我的日期是 NSDates,但使用 NSDateFormatter 作为字符串显示给用户。

我正在使用核心数据。

我当前在 fetchresultscontroller 中的谓词是这样的:

if ([self.timelineSearchBar.text length] > 0) {
    NSPredicate *predName = [NSPredicate predicateWithFormat:@"ANY whoBy.name CONTAINS[c] %@", self.timelineSearchBar.text];
    NSPredicate *predOccasion = [NSPredicate predicateWithFormat:@"ANY occasion.title CONTAINS[c] %@", self.timelineSearchBar.text];
    NSPredicate *predDate = [NSPredicate predicateWithFormat:@"ANY dates.dateOfEvent CONTAINS[c] %@", self.timelineSearchBar.text];


NSPredicate *compPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predName, predOccasion, predDate]];
[fetchRequest setPredicate:compPredicate];

有了它,我可以搜索“名称”和“场合标题”。但是,我无法搜索日期。

日期格式为:

-(NSString *)sectionDateFormatter
{
    // this can be fancier if you need a custom format or particular timezone:
    return [NSDateFormatter localizedStringFromDate:self.dates.dateOfEvent
                                          dateStyle:NSDateFormatterLongStyle
                                          timeStyle:NSDateFormatterNoStyle];
}

但是,当我搜索任何日期时,它根本不显示。无论如何我也可以在这里搜索日期(无需创建另一个 fetchedResultsController 等)?

谢谢,欢迎提出任何想法!

编辑:包括我如何保存日期

NSCalendar *cal = [NSCalendar currentCalendar];

NSDateComponents *components = [cal
                                components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
                                fromDate:self.datePicker.date];
NSDate *selectedDate = [cal dateFromComponents:components];

【问题讨论】:

    标签: ios objective-c search core-data nspredicate


    【解决方案1】:

    NSPredicate 将允许使用典型的比较运算符搜索日期。但请记住,用户对日期的理解比设备更模糊,因此搜索几乎总是应该包含不等式......

    NSDate *startDate = // date from the user's input, minus a little, like to the start of the specified day
    NSDate *endDate = // date from the user's input, plus a little, like to the end of the specified day
    
    NSPredicate *dateRangePredicate = [NSPredicate predicateWithFormat:@"(dateOfEvent >= %@) AND (dateOfEvent <= %@)", startDate, endDate];
    NSPredicate *compPredicate = [NSCompoundPredicate // as you have it
    

    【讨论】:

    • 请务必检查我的谓词字符串,因为我不知道您的模型的结构。
    • 非常感谢 - 非常感谢!我的问题是..(甚至可能是一个不同的问题)是..我将如何获得 startDate 和 endDate?我已经编辑了我的问题,以包括如何将日期保存到 Core Data(根本没有时间) - 我将如何生成 startDate?对不起,这里是一个公平的新手!
    • 添加到我之前的评论中,当核心数据信息已经保存时,我正在另一个视图控制器中执行 fetchRequest。因此,我是否应该在我的“日期”实体中创建其他属性来保存开始和结束日期,然后我可以在 NSFetchedResultsController 中引用,或者这是否过于复杂?
    • 一般来说,将 NSDates 视为表示日期的唯一方法。 NSString 仅用于最后一步,向人类显示日期。换句话说,一旦用户输入完成,就将其转换为日期。在 CoreData 中仅存储 NSDates 并使用 NSDates 进行所有搜索计算。检索到记录后,您可以使用日期格式化程序为用户创建字符串。
    • 感谢@danh,当然,在搞砸了很长时间的日期之后,我学会了在 Core Data 中将日期存储为 NSDates,并以友好的方式将其显示给用户。我现在明白你的答案了——我只是不确定是否应该在 NSDate 类型的 Dates 实体中创建两个名为 startDate 和 endDate 的新属性——将它们保存在 save 方法中,然后在单独的表视图中引用这些对象?我了解这个概念 - 只是想确保我了解放置所有内容的位置
    【解决方案2】:

    试试这个

        NSCalendar *calendar = [NSCalendar currentCalendar];
        NSDateComponents *components;
    
        // Today starts today - remove any time components
        components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit ) fromDate:date];
        _todayStartDate = [calendar dateFromComponents:components];
    
        // Tomorrow starts tomorrow so add one day
        [components setMonth:0];
        [components setDay:1]; //reset the other components
        [components setYear:0]; //reset the other components
        _tomorrowsStartDate = [calendar dateByAddingComponents:components toDate:_todayStartDate options:0];
    
        NSPredicate *dateRangePredicate = [NSPredicate predicateWithFormat:@"(dateOfEvent >= %@) AND (dateOfEvent < %@)", _todayStartDate, _tomorrowsStartDate];
    

    在将 NSDate 存储到 Core Data 之前,请确保从 NSDate 中删除所有时间组件,这将允许您使用 "dateOfEvent==%@", _todayStartDate 进行搜索

            NSCalendar *cal = [NSCalendar currentCalendar];
    
            NSDateComponents *components = [cal
                      components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
                                    fromDate:self.datePicker.date];
            NSDate *selectedDate = [cal dateFromComponents:components];
    
            // Remove any time components
            NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit ) fromDate: selectedDate];
            NSDate *dateToStore = [calendar dateFromComponents:dateComponents];
    

    编辑:

    我刚刚意识到搜索使用的是输入到 searchBar 中的文本,因此上述方法不起作用,因为我们需要匹配一个字符串。可能无法将用户在 searchBar 中输入的内容转换为 NSDate。我通过创建一个 NSManagedObject 子类并在子类上创建一个方法来将日期转换为字符串来解决这个问题。使用这种方法,我在对象上设置了一个名为 'found' 的瞬态属性,然后使用此属性过滤显示的列表 - 实际上,由于分层结构,我只是突出显示结构中包含匹配节点的元素。

    - (NSString*)stringFromDate:(NSDate*)date {
    
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
        return [dateFormatter stringFromDate:date];
    }
    

    然后在同一个子类上一个方法来检查属性值是否包含搜索字符串

        - (BOOL)checkAttribute:(NSString*)value searchString:(NSString*)searchString
        {
            if (searchString == nil || value == nil) return NO;
    
            NSRange range = [value rangeOfString:searchString options:NSCaseInsensitiveSearch];
            if (range.location == NSNotFound) {
                return NO;
            }
            else {
                return YES;
            }
    }
    

    最后是一堆搜索方法,它们也将搜索任何子节点

    - (BOOL)containsSearchString:(NSString*)string
    {
        // Start of a search so reset found.
        self.found = NO;
    
        _lastSearchString = string;
        if ([self containsString:string])
            self.found = YES;
    
        if ([self childContainsString:string])
            self.found = YES;
    
        return self.found;
    
    }
    -(BOOL)containsString:(NSString*)searchString
    {
        if ([self checkAttribute:self.displayName searchString:searchString])
            return YES;
        if ([self checkAttribute:self.reminderPeriod searchString:searchString])
            return YES;
        if ([self checkAttribute:[self stringFromDate:self.reminderDate] searchString:searchString])
            return YES;
        if ([self checkAttribute:self.details.string searchString:searchString])
            return YES;
    
        return NO;
    }
    - (BOOL)childContainsString:(NSString*)searchString {
    
        for (OSTreeNode *child in self.children) {
    
            if ([child containsSearchString:searchString])
                self.found = YES;
    
        }
    
        return self.found;
    }
    

    【讨论】:

    • 谢谢邓肯 - 这很有帮助!只是一个简单的问题 - 我是否将它放在表格视图的 NSFetchedResultsController 方法中.. 和 fromDate:date - 这里的日期可以来自核心数据(在我的情况下,dateOfEvent),还是在我之前的保存方法中这样做保存到核心数据,因此在我的日期实体中创建一个今天开始日期和明天开始日期 NSDate 属性?我希望这是有道理的..所以重申..我的问题是,这段代码应该去哪里,今天开始日期和明天开始日期应该是我的“日期”实体中的 NSDate 属性吗?再次感谢!
    • Ummm... 好的,抱歉,您正在尝试使用在 searchBar 中输入的字符串来搜索数据库中的日期!这是行不通的,因为 fromDate:??参数必须是日期,因此必须先将输入到 searchBar 中的任何内容转换为 NSDate - 如果它只是一个字符串,这可能会很困难!
    • 谢谢 Duncan - 抱歉,这很令人困惑,但这是有道理的.. searchBar 永远无法搜索 Date!哇..我必须弄清楚这个!再次感谢杜纳肯
    • 您可以通过将日期作为字符串存储在 Core Data 中来解决此问题,然后使用 'CONTAINS [cd] %@' 的原始方法将起作用。但是,您将被用于存储 stringDate 的任何日期格式卡住。例如 '01/01/2013' 或 '1 Jan 2013' 或 '01-01-2013' 等...您还需要转换时区差异。
    • 当然,您可以创建一个包含所有可能日期格式的字符串 '01-01-2013 1 January 2013 01/01/2013 1 Jan 2013' - 这也可以!
    猜你喜欢
    • 1970-01-01
    • 2011-06-29
    • 1970-01-01
    • 1970-01-01
    • 2016-06-21
    • 2013-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多