我对这个还不是很熟悉,请耐心等待。
我使用《iOS编程指南:大牛们的寻宝之旅》第四版构建了一个名为Homepwner的应用程序,该应用程序利用归档在应用程序进入后台时存储信息,并在再次启动时加载信息,效果非常好。我决定为自己的名为SBL的应用程序实现相同的策略,但是当应用程序在退出后重新加载时,数据似乎已经加载但不能正确显示。
该应用程序在表格中显示“CCIEvent”的数组,它们看起来像这样:
7:00 AM: 湿和脏尿布
8:48 AM: 喂养-两个-20分钟
9:48 AM: 小睡-1小时0分钟
但是当我退出应用程序并重新启动时,列表会像这样拉起(我必须将其标识为代码才能发布此帖子,但下面的信息会在我的表格上屏幕上显示):
<CCIEvent: 0x154e44e20>
<CCIEvent: 0x154e2c7b0>
<CCIEvent: 0x154e77b90>
我很不确定该看哪里,但以下是与保存/加载相关的所有代码(我想):
在CCIEvent.m文件中:
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.startTime forKey:@"startTime"];
[aCoder encodeObject:self.bedTime forKey:@"bedTime"];
[aCoder encodeObject:self.wakeTime forKey:@"wakeTime"];
[aCoder encodeBool:self.isNap forKey:@"isNap"];
[aCoder encodeInt:self.feedDuration forKey:@"feedDuration"];
[aCoder encodeInt:self.sourceIndex forKey:@"sourceIndex"];
[aCoder encodeInt:self.diaperIndex forKey:@"diaperIndex"];
[aCoder encodeObject:self.note forKey:@"note"];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
_startTime = [aDecoder decodeObjectForKey:@"startTime"];
_bedTime = [aDecoder decodeObjectForKey:@"bedTime"];
_wakeTime = [aDecoder decodeObjectForKey:@"wakeTime"];
_isNap = [aDecoder decodeBoolForKey:@"isNap"];
_feedDuration = [aDecoder decodeIntForKey:@"feedDuration"];
_sourceIndex = [aDecoder decodeIntForKey:@"sourceIndex"];
_diaperIndex = [aDecoder decodeIntForKey:@"diaperIndex"];
_note = [aDecoder decodeObjectForKey:@"note"];
}
return self;
}
在CCIEventStore.m中。
- (instancetype)initPrivate
{
self = [super init];
if (self) {
NSString *path = [self eventArchivePath];
_privateEvents = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
// If the array hadn't been saved previously, create an empty one
if (!_privateEvents) {
_privateEvents = [[NSMutableArray alloc] init];
NSLog(@"Did NOT load events");
} else {
NSLog(@"Loaded events");
}
}
return self;
}
- (CCIEvent *)createEventWithEventType:(NSString *)eventType
startTime:(NSDate *)startTime
bedTime:(NSDate *)bedTime
wakeTime:(NSDate *)wakeTime
isNap:(BOOL)isNap
feedDuration:(int)feedDuration
sourceIndex:(int)sourceIndex
diaperIndex:(int)diaperIndex
note:(NSString *)note
{
CCIEvent *event = [[CCIEvent alloc] initWithEventType:eventType
startTime:startTime
bedTime:bedTime
wakeTime:wakeTime
isNap:isNap
feedDuration:feedDuration
sourceIndex:sourceIndex
diaperIndex:diaperIndex
note:note];
[self.privateEvents addObject:event];
return event;
}
- (NSString *)eventArchivePath
{
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [documentDirectories firstObject];
return [documentDirectory stringByAppendingPathComponent:@"events.archive"];
}
- (BOOL)saveChanges
{
NSString *path = [self eventArchivePath];
return [NSKeyedArchiver archiveRootObject:self.privateEvents
toFile:path];
}
在AppDelegate.m文件中
- (void)applicationDidEnterBackground:(UIApplication *)application {
BOOL success = [[CCIEventStore sharedStore] saveChanges];
if (success) {
NSLog(@"Saved all of the CCIEvents");
} else {
NSLog(@"Could not save any of the CCIEvents");
}
}
这是我称之为CCILogViewController.m的视图控制器中包含表格的一些代码:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
[dateFormatter setDateStyle:NSDateFormatterShortStyle];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"
forIndexPath:indexPath];
CCIEvent *event = self.sortedAndFilteredArray[indexPath.row];
if ([event.eventType isEqualToString:@"sleepEvent"] && event.wakeTime) {
NSDateComponents *dateComponentsToday = [[NSCalendar currentCalendar] components:NSCalendarUnitYear fromDate:[NSDate date]];
NSInteger yearToday = [dateComponentsToday year];
NSInteger dayOfYearToday = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitYear
forDate:[NSDate date]];
NSDateComponents *dateComponentsEvent = [[NSCalendar currentCalendar] components:NSCalendarUnitYear
fromDate:event.startTime];
NSInteger yearEvent = [dateComponentsEvent year];
NSInteger dayOfYearEvent = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitYear
forDate:event.startTime];
NSInteger dayOfYearWakeEvent;
dayOfYearWakeEvent = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitYear
forDate:event.wakeTime];
if (event.wakeTime && yearEvent == yearToday && dayOfYearEvent == dayOfYearToday - 1 && dayOfYearWakeEvent == dayOfYearToday) {
cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", [dateFormatter stringFromDate:event.startTime], [self.sortedAndFilteredArray[indexPath.row] description]];
} else if (event.wakeTime && yearEvent == yearToday - 1 && dayOfYearEvent == dayOfYearToday - 1 && dayOfYearEvent == 1 && dayOfYearWakeEvent == dayOfYearToday) {
cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", [dateFormatter stringFromDate:event.startTime], [self.sortedAndFilteredArray[indexPath.row] description]];
} else {
cell.textLabel.text = [self.sortedAndFilteredArray[indexPath.row] description];
}
} else if (self.dateOptionIndex == 2 || self.dateOptionIndex == 3) {
cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", [dateFormatter stringFromDate:event.startTime], [self.sortedAndFilteredArray[indexPath.row] description]];
} else {
cell.textLabel.text = [self.sortedAndFilteredArray[indexPath.row] description];
}
if (event.note) {
cell.accessoryType = UITableViewCellAccessoryDetailButton;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
以下是我获取的sortedAndFilteredArray的方法,它被称为在多个地方包括viewWillAppear中:
- (void)sortAndFilterArray
{
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"startTime" ascending:self.arrayIsAscending];
NSArray *sortedArray = [[[CCIEventStore sharedStore] allEvents] sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
NSMutableArray *sortedAndFilteredArray = [[NSMutableArray alloc] init];
NSMutableArray *finalArray = [[NSMutableArray alloc] init];
for (CCIEvent *event in sortedArray) {
switch (self.eventOptionIndex) {
case 1:
if ([event.eventType isEqualToString:@"sleepEvent"]) {
[sortedAndFilteredArray addObject:event];
}
break;
case 2:
if ([event.eventType isEqualToString:@"feedEvent"]) {
[sortedAndFilteredArray addObject:event];
}
break;
case 3:
if ([event.eventType isEqualToString:@"diaperEvent"]) {
[sortedAndFilteredArray addObject:event];
}
break;
default:
[sortedAndFilteredArray addObject:event];
break;
}
}
NSDateComponents *dateComponentsToday = [[NSCalendar currentCalendar] components:NSCalendarUnitYear fromDate:[NSDate date]];
NSInteger yearToday = [dateComponentsToday year];
NSInteger dayOfYearToday = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitYear
forDate:[NSDate date]];
for (CCIEvent *event in sortedAndFilteredArray) {
NSDateComponents *dateComponentsEvent = [[NSCalendar currentCalendar] components:NSCalendarUnitYear
fromDate:event.startTime];
NSInteger yearEvent = [dateComponentsEvent year];
NSInteger dayOfYearEvent = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitYear
forDate:event.startTime];
NSInteger dayOfYearWakeEvent;
switch (self.dateOptionIndex) {
case 0:
dayOfYearWakeEvent = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitYear
forDate:event.wakeTime];
// Filter here for dateIndex 0 (Today)
if ([event.eventType isEqualToString:@"sleepEvent"] && event.wakeTime && yearEvent == yearToday && dayOfYearEvent == dayOfYearToday - 1 && dayOfYearWakeEvent == dayOfYearToday) {
[finalArray addObject:event];
} else if ([event.eventType isEqualToString:@"sleepEvent"] && event.wakeTime && yearEvent == yearToday - 1 && dayOfYearEvent == dayOfYearToday - 1 && dayOfYearEvent == 1 && dayOfYearWakeEvent == dayOfYearToday) {
[finalArray addObject:event];
} else if (yearEvent == yearToday && dayOfYearEvent == dayOfYearToday) {
[finalArray addObject:event];
}
break;
case 1:
// Filter here for dateIndex 1 (Yesterday)
if (yearEvent == yearToday && dayOfYearEvent == dayOfYearToday - 1) {
[finalArray addObject:event];
} else if (yearEvent == yearToday - 1 && dayOfYearEvent == dayOfYearToday - 1 && dayOfYearEvent == 1) {
[finalArray addObject:event];
}
break;
case 2:
// Filter here for dateIndex 2 (Past Week)
if (yearEvent == yearToday && dayOfYearEvent >= dayOfYearEvent - 6) {
[finalArray addObject:event];
} else if (yearEvent == yearToday - 1 && dayOfYearEvent >= dayOfYearToday - 6 && dayOfYearEvent < 7) {
[finalArray addObject:event];
}
break;
default:
// No filter here for dateIndex 3 (All Time)
[finalArray addObject:event];
break;
}
}
self.sortedAndFilteredArray = [finalArray copy];
}
获取CCIEvent描述时所调用的内容如下:
- (NSString *)description
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
[dateFormatter setDateStyle:NSDateFormatterNoStyle];
if ([self.eventType isEqualToString:@"sleepEvent"]) {
NSString *bedTimeString = [dateFormatter stringFromDate:self.bedTime];
NSString *wakeTimeString = [dateFormatter stringFromDate:self.wakeTime];
long min = self.sleepDuration/60;
long hrs = self.sleepDuration/60/60;
long rMinutes = min - hrs * 60;
if (!self.wakeTime && self.bedTime) {
if (self.isNap) {
return [[NSString alloc] initWithFormat:@"%@: Went Down for Nap", bedTimeString];
} else {
return [[NSString alloc] initWithFormat:@"%@: Went Down", bedTimeString];
}
} else if (self.wakeTime && !self.bedTime) {
if (self.isNap) {
return [[NSString alloc] initWithFormat:@"%@: Woke from Nap", wakeTimeString];
} else {
return [[NSString alloc] initWithFormat:@"%@: Woke", wakeTimeString];
}
} else if (self.sleepDuration <= 60) {
if (self.isNap) {
return [[NSString alloc] initWithFormat:@"%@: Napped - 1 min", bedTimeString];
} else {
return [[NSString alloc] initWithFormat:@"%@: Slept - 1 min", bedTimeString];
}
} else if (self.sleepDuration > 60 && self.sleepDuration < 60 * 60){
if (self.isNap) {
return [[NSString alloc] initWithFormat:@"%@: Napped - %ld min", bedTimeString, min];
} else {
return [[NSString alloc] initWithFormat:@"%@: Slept - %ld min", bedTimeString, min];
}
} else if (hrs == 1) {
if (self.isNap) {
return [[NSString alloc] initWithFormat:@"%@: Napped - 1 hr %ld min", bedTimeString, rMinutes];
} else {
return [[NSString alloc] initWithFormat:@"%@: Slept - 1 hr %ld min", bedTimeString, rMinutes];
}
} else {
if (self.isNap) {
return [[NSString alloc] initWithFormat:@"%@: Napped - %ld hrs %ld min", bedTimeString, hrs, rMinutes];
} else {
return [[NSString alloc] initWithFormat:@"%@: Slept - %ld hrs %ld min", bedTimeString, hrs, rMinutes];
}
}
} else if ([self.eventType isEqualToString:@"feedEvent"]) {
NSString *startTimeString = [dateFormatter stringFromDate:self.startTime];
NSArray *sourceArray = @[@"Both", @"Left", @"Right", @"Bottle"];
NSString *sourceString = sourceArray[self.sourceIndex];
return [[NSString alloc] initWithFormat:@"%@: Fed - %@ - %d min", startTimeString, sourceString, self.feedDuration / 60];
} else if ([self.eventType isEqualToString:@"diaperEvent"]) {
NSString *startTimeString = [dateFormatter stringFromDate:self.startTime];
NSArray *diaperArray = @[@"Wet and Dirty", @"Wet", @"Dirty"];
NSString *diaperString = diaperArray[self.diaperIndex];
return [[NSString alloc] initWithFormat:@"%@: %@ Diaper", startTimeString, diaperString];
}
return [super description];
}
cell.textLabel.text = [self.sortedAndFilteredArray[indexPath.row] description];
- 3vangelos