开发者

Obj-C, How to store / retrieve several date ranges and evaluate it for use based on past or future, least code possible?

I need to quickly produce some functions which will allow me to store and retrieve some date ranges. Then evaluate the dates based on todays date, then add them to an array.

I'm not exactly sure how many ranges I'll need to ke开发者_如何学Goep.

Perhaps you've seen a similar example of this I can use for reference?

EDIT. I need to save them for use when the app is next run too.


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


You might look at this question for an example of checking if an NSDate falls between two other NSDate's. I would suggest creating a "MyDateRange" class with "beginDate" and "endDate" properties and a -containsDate: method.

If you don't know how many ranges you'll need to keep, an NSMutableArray might be a good way to store them, because it grows as needed when you add objects.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜