Search code examples
iosobjective-ccore-datansdatensfetchrequest

Retrieve the next day not included in a CoreData request result


I would like to get the next available day by starting my search from today and excluding the dates provided by a Core Data request.

my initialization code, and a helping method implemented in the same class

+ (NSDate *)getDateByAddingDays:(NSInteger)days toDate:(NSDate *)date {
    NSDate *newdate = [[NSDate alloc]init];
    if (days != 0) {
        NSDateComponents *components = [[NSDateComponents alloc] init];
        components.day = days;
        NSCalendar *calendar = [NSCalendar currentCalendar];
        newdate = [calendar dateByAddingComponents:components toDate:date
                                           options:0];
    }
    return newdate;
}

+ (void)myTroublesomeMethod {

    // standard initialization of NSFetchRequest
    NSManagedObjectContext *context = [(id)[[UIApplication sharedApplication] delegate] managedObjectContext];

    NSDate *today = [NSDate date];

    NSFetchRequest *request3 = [[NSFetchRequest alloc] init];
    NSEntityDescription *chiusureDescription = [NSEntityDescription entityForName:@"Chiusure" inManagedObjectContext:context];
    NSError *error;
    [request3 setEntity:chiusureDescription];
    NSArray *arrayChiusure = [context executeFetchRequest:request3 error:&error];

    // I then extract the "data" attribute, that stores the date to be excluded

    NSMutableArray *giorniChiusura = [[NSMutableArray alloc]init];
        for (Chiusure *entity in arrayChiusure) {
            [giorniChiusura addObject:(NSDate*) entity.data];
        }

    // and here is where the problem rises:

    NSInteger days = 0;
    NSDate *nextDate = [self getDateByAddingDays:days toDate:today];
    if ([arrayChiusure containsObject:nextDate]) {

        // HERE is the error, I suppose. nextDate is never contained in arrayChiusure, so the next while statement is an infinite loop.

        while ([arrayChiusure containsObject:nextDate]) {
            days += 1;
            nextDate = [self getDateByAddingDays:days toDate:today];
        }

    // OMITTED: use of nextDate somewhere later in my code
}

ALTERNATIVE APPROACHES I'VE THOUGHT AT:

  • I understand that I can make a new NSFetchRequest inside the while loop in order to check if the proposed nextDate is included into Chiusure Entity dataset but it seems overkilling to me.

ADDITIONAL INFO:

  • arrayChiusure is expected to contain 10-20 entities at maximum
  • I suppose the error is related to a wrong comparison (i.e. in [arrayChiusure containsObject:nextDate]) but I do not understand why

any help is appreciated :) thanks in advance


Solution

  • As already mentioned in a comment, the problem is that NSDate represents not only the day, but also the time up to milli-seconds. Therefore you have to "normalize" the date first to represent the current day at midnight (or whatever is store in the Core Data objects).

    However, there is an easier solution: You can create a fetch request that returns only the most recent date already present in the store (see https://stackoverflow.com/a/18395185/1187415 for an example) and then add one day to it.

    Example:

    NSArray *arrayChiusure = [context executeFetchRequest:request3 error:&error];
    
    // Extract "data" attribute into new array:
    NSArray *giorniChiusura = [arrayChiusure valueForKey:@"data"];
    
    // nextDate = "today at midnight":
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDate *today = [NSDate date];
    NSDate *nextDate;
    [calendar rangeOfUnit:NSDayCalendarUnit startDate:&nextDate interval:NULL forDate:today];
    
    // Find next available day:
    NSDateComponents *oneDay = [[NSDateComponents alloc]init];
    oneDay.day = 1;
    while ([giorniChiusura containsObject:nextDate]) {
        nextDate = [calendar dateByAddingComponents:oneDay toDate:nextDate options:0];
    }