Skip to content

Commit c752cb6

Browse files
Merge pull request #50 from flexibits/will/fix/cache-current-calendar
Cache `+[NSCalendar currentCalendar]`
2 parents a3b002b + 2ea9fee commit c752cb6

File tree

2 files changed

+91
-27
lines changed

2 files changed

+91
-27
lines changed

Headers/Foundation/NSCalendar.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ GS_EXPORT_CLASS
249249
{
250250
@private
251251
void *_NSCalendarInternal;
252-
NSLock *_lock;
252+
NSRecursiveLock *_lock;
253253
}
254254

255255
/**

Source/NSCalendar.m

Lines changed: 90 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ - (NSString *) _localeIdentifier;
114114
- (void) _setLocaleIdentifier: (NSString*)identifier;
115115
@end
116116

117+
static NSCalendar *currentCalendar = nil;
117118
static NSCalendar *autoupdatingCalendar = nil;
118119
static NSRecursiveLock *classLock = nil;
119120

@@ -123,6 +124,52 @@ - (void) _setLocaleIdentifier: (NSString*)identifier;
123124

124125
@implementation NSCalendar (PrivateMethods)
125126

127+
- (BOOL) _needsRefreshForLocale: (NSString *)locale
128+
calendar: (NSString *)calendar
129+
timeZone: (NSString *)timeZone
130+
{
131+
BOOL needsToRefresh;
132+
133+
[_lock lock];
134+
135+
needsToRefresh = [locale isEqual:my->localeID] == NO
136+
|| [calendar isEqual:my->identifier] == NO
137+
|| [timeZone isEqual:[my->tz name]] == NO;
138+
139+
[_lock unlock];
140+
141+
return needsToRefresh;
142+
}
143+
144+
- (BOOL) _needsRefreshForDefaultsChangeNotification: (NSNotification *)n
145+
{
146+
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
147+
NSString *locale = [defs stringForKey:@"Locale"];
148+
NSString *calendar = [defs stringForKey:@"Calendar"];
149+
NSString *tz = [defs stringForKey:@"Local Time Zone"];
150+
BOOL needsToRefresh = [self _needsRefreshForLocale:locale calendar:calendar timeZone:tz];
151+
152+
return needsToRefresh;
153+
}
154+
155+
+ (void) _refreshCurrentCalendarFromDefaultsDidChange: (NSNotification*)n
156+
{
157+
[classLock lock];
158+
159+
if (currentCalendar != nil)
160+
{
161+
BOOL needToRefreshCurrentCalendar = [currentCalendar _needsRefreshForDefaultsChangeNotification:n];
162+
163+
if (needToRefreshCurrentCalendar)
164+
{
165+
RELEASE(currentCalendar);
166+
currentCalendar = nil;
167+
}
168+
}
169+
170+
[classLock unlock];
171+
}
172+
126173
#if GS_USE_ICU == 1
127174
- (void *) _locked_openCalendarFor: (NSTimeZone *)timeZone
128175
{
@@ -132,7 +179,6 @@ - (void *) _locked_openCalendarFor: (NSTimeZone *)timeZone
132179
const char *cLocaleId;
133180
UErrorCode err = U_ZERO_ERROR;
134181
UCalendarType type;
135-
void *cal;
136182

137183
cLocaleId = [my->localeID UTF8String];
138184
tzName = [timeZone name];
@@ -260,26 +306,25 @@ - (void) _setLocaleIdentifier: (NSString *)identifier
260306

261307
- (void) _defaultsDidChange: (NSNotification*)n
262308
{
263-
NSUserDefaults *defs;
264-
NSString *locale;
265-
NSString *calendar;
266-
NSString *tz;
267-
268-
defs = [NSUserDefaults standardUserDefaults];
269-
locale = [defs stringForKey:@"Locale"];
270-
calendar = [defs stringForKey:@"Calendar"];
271-
tz = [defs stringForKey:@"Local Time Zone"];
309+
BOOL needsToRefresh;
310+
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
311+
NSString *locale = [defs stringForKey:@"Locale"];
312+
NSString *calendar = [defs stringForKey:@"Calendar"];
313+
NSString *tz = [defs stringForKey:@"Local Time Zone"];
272314

273315
[classLock lock];
274316
[_lock lock];
275-
if ([locale isEqual:my->localeID] == NO ||
276-
[calendar isEqual:my->identifier] == NO ||
277-
[tz isEqual:[my->tz name]] == NO) {
317+
318+
needsToRefresh = [self _needsRefreshForLocale:locale calendar:calendar timeZone:tz];
319+
320+
if (needsToRefresh)
321+
{
278322
#if GS_USE_ICU == 1
279-
if (my->cal != NULL) {
323+
if (my->cal != NULL)
324+
{
280325
ucal_close(my->cal);
281326
my->cal = NULL;
282-
}
327+
}
283328
#endif
284329

285330
ASSIGN(my->localeID, locale);
@@ -289,6 +334,7 @@ - (void) _defaultsDidChange: (NSNotification*)n
289334

290335
[self _locked_resetCalendar];
291336
}
337+
292338
[_lock unlock];
293339
[classLock unlock];
294340
}
@@ -298,21 +344,36 @@ @implementation NSCalendar
298344

299345
+ (void) initialize
300346
{
301-
if (self == [NSCalendar class]) {
347+
if (self == [NSCalendar class])
348+
{
302349
classLock = [NSRecursiveLock new];
303-
}
350+
351+
[[NSNotificationCenter defaultCenter] addObserver:self
352+
selector:@selector(_refreshCurrentCalendarFromDefaultsDidChange:)
353+
name:NSUserDefaultsDidChangeNotification
354+
object:nil];
355+
}
304356
}
305357

306358
+ (id) currentCalendar
307359
{
308360
NSCalendar *result;
309-
NSString *identifier;
310361

311-
// This identifier may be nil
312-
identifier = [[NSLocale currentLocale] objectForKey:NSLocaleCalendarIdentifier];
313-
result = [[NSCalendar alloc] initWithCalendarIdentifier:identifier];
362+
[classLock lock];
363+
364+
if (currentCalendar == nil)
365+
{
366+
// This identifier may be nil
367+
NSString *identifier = [[NSLocale currentLocale] objectForKey:NSLocaleCalendarIdentifier];
368+
369+
currentCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:identifier];
370+
}
314371

315-
return AUTORELEASE(result);
372+
result = currentCalendar;
373+
374+
[classLock unlock];
375+
376+
return result;
316377
}
317378

318379
+ (id) autoupdatingCurrentCalendar
@@ -827,6 +888,10 @@ - (NSDate *)dateBySettingUnit:(NSCalendarUnit)unit value:(NSInteger)value ofDate
827888
{
828889
void *cal;
829890
UErrorCode err = U_ZERO_ERROR;
891+
BOOL ok;
892+
UCalendarDateFields ucalField;
893+
NSTimeInterval epochTime;
894+
NSTimeInterval newEpochTime;
830895

831896
[_lock lock];
832897
cal = [self _locked_cloneCalendar:&err];
@@ -840,20 +905,19 @@ - (NSDate *)dateBySettingUnit:(NSCalendarUnit)unit value:(NSInteger)value ofDate
840905
ucal_clear(cal);
841906

842907
// Convert to ICU-equivalent calendar unit
843-
BOOL ok;
844-
UCalendarDateFields ucalField = NSCalendarUnitToUCalendarDateField(unit, &ok);
908+
ucalField = NSCalendarUnitToUCalendarDateField(unit, &ok);
845909
NSAssert(ok, @"GNUStep does not implement the given date field.");
846910

847911
// Set the ICU calendar to this date
848-
NSTimeInterval epochTime = [date timeIntervalSince1970] * SECOND_TO_MILLI;
912+
epochTime = [date timeIntervalSince1970] * SECOND_TO_MILLI;
849913
ucal_setMillis(cal, epochTime, &err);
850914
NSAssert(!U_FAILURE(err), ([NSString stringWithFormat:@"Couldn't setMillis to calendar: %s", u_errorName(err)]));
851915

852916
// Set the field on the ICU calendar
853917
ucal_set(cal, ucalField, value);
854918

855919
// Get the date back from the ICU calendar
856-
NSTimeInterval newEpochTime = ucal_getMillis(cal, &err);
920+
newEpochTime = ucal_getMillis(cal, &err);
857921
ucal_close(cal);
858922

859923
NSAssert(!U_FAILURE(err), ([NSString stringWithFormat:@"Couldn't getMillis from calendar: %s", u_errorName(err)]));

0 commit comments

Comments
 (0)