Skip to content

Commit

Permalink
Fixed re-load view hierarchy bug.
Browse files Browse the repository at this point in the history
This closes issue klazuka#23 on GitHub. The issue was related to how we re-construct the view hierarchy after a low memory warning from the system. If the user had changed to a month different than the initial month when KalViewController was created, it would fail to find the appropriate KalTileView for the value that it had stored as the initially selected date. The solution is to re-cache the initially selected date when a low memory warning occurs.

Original bug report by jgchristian:
Steps to reproduce:
1. Start your Holiday app
2. Slide to the next month (i.e. not the current month)
3. Select an event and view the holiday details
4. When on the details screen, quit to the springboard by single clicking the home button (not double clicking to background). We need to force the device to want to reload the grid when we return - so you may need to do some memory intensive stuff - but not generally the case for me.
5. Relaunch the Holiday app. This returns you to the details screen
6. Now press back to return to the grid. Crash log below

From the looks of the code this is happening because the 'logic' object is still on the next month (correct), but when loadView is triggered by the OS trying to re-instantiate the view it defaults to setting the current date on the grid - which was in the previous month so assertion fails as cell is nil.

Thought about maintaining last user-selected date but started to get fiddly.

2011-02-02 08:20:24.961 Holiday[3471:307] Received memory warning. Level=2
2011-02-02 08:20:28.382 Holiday[3471:307] Assertion failure in -[KalMonthView tileForDate:], /Users/j.christian/dev/Kal/src/KalMonthView.m:84
2011-02-02 08:20:28.510 Holiday[3471:307] Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Failed to find corresponding tile for date 2/2/2011'
  • Loading branch information
klazuka committed Feb 2, 2011
1 parent c4031c0 commit b2e164c
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 16 deletions.
4 changes: 2 additions & 2 deletions Examples/Holiday/Holiday.xcodeproj/project.pbxproj
Expand Up @@ -353,7 +353,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 3.1;
OTHER_LDFLAGS = "-all_load";
PREBINDING = NO;
SDKROOT = iphoneos4.1;
SDKROOT = iphoneos;
USER_HEADER_SEARCH_PATHS = ". ../../src";
};
name = Debug;
Expand All @@ -370,7 +370,7 @@
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
OTHER_LDFLAGS = "-all_load";
PREBINDING = NO;
SDKROOT = iphoneos4.1;
SDKROOT = iphoneos;
USER_HEADER_SEARCH_PATHS = ". ../../src";
};
name = Release;
Expand Down
4 changes: 2 additions & 2 deletions Examples/NativeCal/NativeCal.xcodeproj/project.pbxproj
Expand Up @@ -286,7 +286,7 @@
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-all_load";
PREBINDING = NO;
SDKROOT = iphoneos4.1;
SDKROOT = iphoneos;
};
name = Debug;
};
Expand All @@ -302,7 +302,7 @@
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
OTHER_LDFLAGS = "-all_load";
PREBINDING = NO;
SDKROOT = iphoneos4.1;
SDKROOT = iphoneos;
};
name = Release;
};
Expand Down
4 changes: 2 additions & 2 deletions src/Kal.xcodeproj/project.pbxproj
Expand Up @@ -279,7 +279,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 3.1;
OTHER_LDFLAGS = "-ObjC";
PREBINDING = NO;
SDKROOT = iphoneos4.1;
SDKROOT = iphoneos;
};
name = Debug;
};
Expand All @@ -293,7 +293,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 3.1;
OTHER_LDFLAGS = "-ObjC";
PREBINDING = NO;
SDKROOT = iphoneos4.1;
SDKROOT = iphoneos;
};
name = Release;
};
Expand Down
5 changes: 3 additions & 2 deletions src/KalViewController.h
Expand Up @@ -26,15 +26,16 @@
UITableView *tableView;
id <UITableViewDelegate> delegate;
id <KalDataSource> dataSource;
NSDate *initialSelectedDate;
NSDate *initialDate; // The date that the calendar was initialized with *or* the currently selected date when the view hierarchy was torn down in order to satisfy a low memory warning.
NSDate *selectedDate; // I cache the selected date because when we respond to a memory warning, we cannot rely on the view hierarchy still being alive, and thus we cannot always derive the selected date from KalView's selectedDate property.
}

@property (nonatomic, assign) id<UITableViewDelegate> delegate;
@property (nonatomic, assign) id<KalDataSource> dataSource;
@property (nonatomic, retain, readonly) NSDate *selectedDate;

- (id)initWithSelectedDate:(NSDate *)selectedDate; // designated initializer. When the calendar is first displayed to the user, the month that contains 'selectedDate' will be shown and the corresponding tile for 'selectedDate' will be automatically selected.
- (void)reloadData; // If you change the KalDataSource after the KalViewController has already been displayed to the user, you must call this method in order for the view to reflect the new data.
- (void)showAndSelectDate:(NSDate *)date; // Updates the state of the calendar to display the specified date's month and selects the tile for that date.
- (NSDate *)selectedDate; // The currently selected date. You should only use the actual date components from this NSDate object. The hours/minutes/seconds/timezones are undefined.

@end
33 changes: 25 additions & 8 deletions src/KalViewController.m
Expand Up @@ -31,18 +31,21 @@ void mach_absolute_difference(uint64_t end, uint64_t start, struct timespec *tp)
NSString *const KalDataSourceChangedNotification = @"KalDataSourceChangedNotification";

@interface KalViewController ()
@property (nonatomic, retain, readwrite) NSDate *initialDate;
@property (nonatomic, retain, readwrite) NSDate *selectedDate;
- (KalView*)calendarView;
@end

@implementation KalViewController

@synthesize dataSource, delegate;
@synthesize dataSource, delegate, initialDate, selectedDate;

- (id)initWithSelectedDate:(NSDate *)selectedDate
- (id)initWithSelectedDate:(NSDate *)date
{
if ((self = [super init])) {
logic = [[KalLogic alloc] initForDate:selectedDate];
initialSelectedDate = [selectedDate retain];
logic = [[KalLogic alloc] initForDate:date];
self.initialDate = date;
self.selectedDate = date;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(significantTimeChangeOccurred) name:UIApplicationSignificantTimeChangeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadData) name:KalDataSourceChangedNotification object:nil];
}
Expand Down Expand Up @@ -94,6 +97,7 @@ - (void)significantTimeChangeOccurred

- (void)didSelectDate:(KalDate *)date
{
self.selectedDate = [date NSDate];
NSDate *from = [[date NSDate] cc_dateByMovingToBeginningOfDay];
NSDate *to = [[date NSDate] cc_dateByMovingToEndOfDay];
[self clearTable];
Expand Down Expand Up @@ -169,21 +173,33 @@ - (NSDate *)selectedDate
// -----------------------------------------------------------------------------------
#pragma mark UIViewController

- (void)didReceiveMemoryWarning
{
self.initialDate = self.selectedDate; // must be done before calling super
[super didReceiveMemoryWarning];
}

- (void)loadView
{
if (!self.title)
self.title = @"Calendar";
KalView *kalView = [[KalView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] delegate:self logic:logic];
KalView *kalView = [[[KalView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] delegate:self logic:logic] autorelease];
self.view = kalView;
tableView = kalView.tableView;
tableView.dataSource = dataSource;
tableView.delegate = delegate;
[tableView retain];
[kalView selectDate:[KalDate dateFromNSDate:initialSelectedDate]];
[kalView release];
[kalView selectDate:[KalDate dateFromNSDate:self.initialDate]];
[self reloadData];
}

- (void)viewDidUnload
{
[super viewDidUnload];
[tableView release];
tableView = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
Expand All @@ -202,7 +218,8 @@ - (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationSignificantTimeChangeNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:KalDataSourceChangedNotification object:nil];
[initialSelectedDate release];
[initialDate release];
[selectedDate release];
[logic release];
[tableView release];
[super dealloc];
Expand Down

0 comments on commit b2e164c

Please sign in to comment.