You can represent a date range in two ways:
- start date + end date
- start date + duration
You can then represent a date as an NSDate instance, as a double (or, if you desperately need to save memory, as an int, like UNIX timestamp). I'd make a class for that.
@interface DateRange : NSObject <NSCoding>
{
NSTimeInterval start, end;
}
@property (nonatomic, assign) NSDate* startDate;
@property (nonatomic, assign) NSDate* endDate;
@property (nonatomic, assign) NSTimeInterval duration;
- (BOOL) containsDate: (NSDate *) date;
@end
@implementation DateRange
- (NSDate *) startDate
{
return [NSDate dateWithTimeIntervalSinceReferenceDate: start];
}
- (void) setStartDate: (NSDate *) date
{
start = [date timeIntervalSinceReferenceDate];
}
- (NSDate *) endDate
{
return [NSDate dateWithTimeIntervalSinceReferenceDate: end];
}
- (void) setEndDate: (NSDate *) date
{
end = [date timeIntervalSinceReferenceDate];
}
- (NSTimeInterval) duration
{
return end - start;
}
- (void) setDuration: (NSTimeInterval) newDuration
{
end = start + newDuration;
}
- (BOOL) containsDate: (NSDate *) date
{
NSTimeInterval d = [date timeIntervalSinceReferenceDate];
return d > start && d < end;
}
- (id) initWithCoder: (NSCoder *) coder
{
if ( ( self = [super init] ) ) {
start = [coder decodeDoubleForKey: @"start"];
end = [coder decodeDoubleForKey: @"end"];
}
return self;
}
- (void) encodeWithCoder: (NSCoder *) coder
{
[coder encodeDouble: start forKey: @"start"];
[coder encodeDouble: end forKey: @"end"];
}
- (BOOL) isEqual: (id) dateRange
{
if ( [self class] != [dateRange class] )
return NO;
return [self.startDate isEqualToDate: ((DateRange *)dateRange).startDate] && [self.endDate isEqualToDate: ((DateRange *)dateRange).endDate];
}
- (NSInteger) hash
{
return (NSInteger) (end - start);
}
@end
The bonus point is that you can store as many ranges in Cocoa collections (such as NSArray) as needed. I leave a better implementation of -isEqual:
and -hash
as an exercise to you, dear reader.
To save a DateRange object in NSUserDefaults:
NSData *dateRangeArchive = [NSKeyedArchiver archivedDataWithRootObject: dateRange];
[[NSUserDefaults standardUserDefaults] setObject: dateRangeArchive forKey: myKey];
To read a DateRange object from NSUserDefaults:
DateRange *dr = [NSKeyedUnarchiver unarchiveObjectWithData: [[NSUserDefaults standardUserDefaults] dataForKey: myKey]]; // returns an autoreleased DateRange object
Similarly, if you need to store an NSArray of DateRanges, you can either archive the whole array or create an array of archived DateRanges (the former should be faster):
NSData *dateRangeArchive = [NSKeyedArchiver archivedDataWithRootObject: arrayOfDateRanges];
[[NSUserDefaults standardUserDefaults] setObject: dateRangeArchive forKey: myKey];
If you think that's too much repetitive code for your project, you can extend NSUserDefaults like this:
@interface NSUserDefaults (MyExtensions)
- (DateRange *) dateRangeForKey: (NSString *) defaultName;
- (void) setDateRange: (DateRange *) dateRange forKey: (NSString *) defaultName;
@end
@implementation NSUserDefaults (MyExtensions)
- (DateRange *) dateRangeForKey: (NSString *) defaultName
{
return [NSKeyedUnarchiver unarchiveObjectWithData: [self dataForKey: defaultName]];
}
- (void) setDateRange: (DateRange *) dateRange forKey: (NSString *) defaultName
{
[self setObject: [NSKeyedArchiver archivedDataWithRootObject: dateRange] forKey: defaultName];
}
@end