Skip to content

Commit b2e164c

Browse files
committed
Fixed re-load view hierarchy bug.
This closes issue #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'
1 parent c4031c0 commit b2e164c

File tree

5 files changed

+34
-16
lines changed

5 files changed

+34
-16
lines changed

Examples/Holiday/Holiday.xcodeproj/project.pbxproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@
353353
IPHONEOS_DEPLOYMENT_TARGET = 3.1;
354354
OTHER_LDFLAGS = "-all_load";
355355
PREBINDING = NO;
356-
SDKROOT = iphoneos4.1;
356+
SDKROOT = iphoneos;
357357
USER_HEADER_SEARCH_PATHS = ". ../../src";
358358
};
359359
name = Debug;
@@ -370,7 +370,7 @@
370370
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
371371
OTHER_LDFLAGS = "-all_load";
372372
PREBINDING = NO;
373-
SDKROOT = iphoneos4.1;
373+
SDKROOT = iphoneos;
374374
USER_HEADER_SEARCH_PATHS = ". ../../src";
375375
};
376376
name = Release;

Examples/NativeCal/NativeCal.xcodeproj/project.pbxproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@
286286
ONLY_ACTIVE_ARCH = YES;
287287
OTHER_LDFLAGS = "-all_load";
288288
PREBINDING = NO;
289-
SDKROOT = iphoneos4.1;
289+
SDKROOT = iphoneos;
290290
};
291291
name = Debug;
292292
};
@@ -302,7 +302,7 @@
302302
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
303303
OTHER_LDFLAGS = "-all_load";
304304
PREBINDING = NO;
305-
SDKROOT = iphoneos4.1;
305+
SDKROOT = iphoneos;
306306
};
307307
name = Release;
308308
};

src/Kal.xcodeproj/project.pbxproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@
279279
IPHONEOS_DEPLOYMENT_TARGET = 3.1;
280280
OTHER_LDFLAGS = "-ObjC";
281281
PREBINDING = NO;
282-
SDKROOT = iphoneos4.1;
282+
SDKROOT = iphoneos;
283283
};
284284
name = Debug;
285285
};
@@ -293,7 +293,7 @@
293293
IPHONEOS_DEPLOYMENT_TARGET = 3.1;
294294
OTHER_LDFLAGS = "-ObjC";
295295
PREBINDING = NO;
296-
SDKROOT = iphoneos4.1;
296+
SDKROOT = iphoneos;
297297
};
298298
name = Release;
299299
};

src/KalViewController.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,16 @@
2626
UITableView *tableView;
2727
id <UITableViewDelegate> delegate;
2828
id <KalDataSource> dataSource;
29-
NSDate *initialSelectedDate;
29+
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.
30+
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.
3031
}
3132

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

3537
- (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.
3638
- (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.
3739
- (void)showAndSelectDate:(NSDate *)date; // Updates the state of the calendar to display the specified date's month and selects the tile for that date.
38-
- (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.
3940

4041
@end

src/KalViewController.m

+25-8
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,21 @@ void mach_absolute_difference(uint64_t end, uint64_t start, struct timespec *tp)
3131
NSString *const KalDataSourceChangedNotification = @"KalDataSourceChangedNotification";
3232

3333
@interface KalViewController ()
34+
@property (nonatomic, retain, readwrite) NSDate *initialDate;
35+
@property (nonatomic, retain, readwrite) NSDate *selectedDate;
3436
- (KalView*)calendarView;
3537
@end
3638

3739
@implementation KalViewController
3840

39-
@synthesize dataSource, delegate;
41+
@synthesize dataSource, delegate, initialDate, selectedDate;
4042

41-
- (id)initWithSelectedDate:(NSDate *)selectedDate
43+
- (id)initWithSelectedDate:(NSDate *)date
4244
{
4345
if ((self = [super init])) {
44-
logic = [[KalLogic alloc] initForDate:selectedDate];
45-
initialSelectedDate = [selectedDate retain];
46+
logic = [[KalLogic alloc] initForDate:date];
47+
self.initialDate = date;
48+
self.selectedDate = date;
4649
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(significantTimeChangeOccurred) name:UIApplicationSignificantTimeChangeNotification object:nil];
4750
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadData) name:KalDataSourceChangedNotification object:nil];
4851
}
@@ -94,6 +97,7 @@ - (void)significantTimeChangeOccurred
9497

9598
- (void)didSelectDate:(KalDate *)date
9699
{
100+
self.selectedDate = [date NSDate];
97101
NSDate *from = [[date NSDate] cc_dateByMovingToBeginningOfDay];
98102
NSDate *to = [[date NSDate] cc_dateByMovingToEndOfDay];
99103
[self clearTable];
@@ -169,21 +173,33 @@ - (NSDate *)selectedDate
169173
// -----------------------------------------------------------------------------------
170174
#pragma mark UIViewController
171175

176+
- (void)didReceiveMemoryWarning
177+
{
178+
self.initialDate = self.selectedDate; // must be done before calling super
179+
[super didReceiveMemoryWarning];
180+
}
181+
172182
- (void)loadView
173183
{
174184
if (!self.title)
175185
self.title = @"Calendar";
176-
KalView *kalView = [[KalView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] delegate:self logic:logic];
186+
KalView *kalView = [[[KalView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] delegate:self logic:logic] autorelease];
177187
self.view = kalView;
178188
tableView = kalView.tableView;
179189
tableView.dataSource = dataSource;
180190
tableView.delegate = delegate;
181191
[tableView retain];
182-
[kalView selectDate:[KalDate dateFromNSDate:initialSelectedDate]];
183-
[kalView release];
192+
[kalView selectDate:[KalDate dateFromNSDate:self.initialDate]];
184193
[self reloadData];
185194
}
186195

196+
- (void)viewDidUnload
197+
{
198+
[super viewDidUnload];
199+
[tableView release];
200+
tableView = nil;
201+
}
202+
187203
- (void)viewWillAppear:(BOOL)animated
188204
{
189205
[super viewWillAppear:animated];
@@ -202,7 +218,8 @@ - (void)dealloc
202218
{
203219
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationSignificantTimeChangeNotification object:nil];
204220
[[NSNotificationCenter defaultCenter] removeObserver:self name:KalDataSourceChangedNotification object:nil];
205-
[initialSelectedDate release];
221+
[initialDate release];
222+
[selectedDate release];
206223
[logic release];
207224
[tableView release];
208225
[super dealloc];

0 commit comments

Comments
 (0)