I once asked a question about how to detect memory leaks when app is running. Thanks for someone who points out that Instruments is the right tool for this purpose.
Unfortunately by using Instruments, no explicit memory leaks are detected. But I found a very bewildering problem. It seems [NSDate date] leaks 16 bytes memory on each call. I soon constructed a very simple app to verify this:
- (void)viewDidLoad {
[super viewDidLoad];
static NSOperationQueue* q;
q = [[NSOperationQueue alloc] init];
[q addOperationWithBlock:^{
while (YES) {
NSDate* date = [NSDate date];
}
}];
}
When the simple app runs, in just about 10 seconds, it's memory usage rockets high to more than 1GB. That explains why one of my App Store app eats up memory gradually on daily usage.
I think it is a glaring bug because the code is so simple that it leaves no room for coding mistakes. But, I post it here so that this can be confirmed so that I can submit a formal bug report to Apple.
EDIT: it seems the bug occurs after I attached to the test app using Instruments and then stops recoding.
EDIT: It seems the above simple code does not always reproduce the bug. Please try the follow:
// Replace the line NSDate* date = [NSDate date] with following line
NSDateComponents* parts = [BingImageDate getDateParts:[NSDate date] ofCulture:@"en-US"];
//BingImageDate.h
#import <Foundation/Foundation.h>
@interface BingImageDate : NSObject
+ (NSDateComponents *)getDateParts:(NSDate *)date ofCulture:(NSString*)culture;
@end
//BingImageDate.m
#import "BingImageDate.h"
static NSCalendar* _gregorian;
static NSTimeZone* _TZ_PST;
static NSDictionary* _cultureHourOffset;
@implementation BingImageDate
+ (void)initialize
{
_gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
_gregorian.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
_TZ_PST = [NSTimeZone timeZoneWithAbbreviation:@"PST"];
_cultureHourOffset = @{
@"de-DE": @1500,
@"en-AU": @700,
@"en-CA": @2100,
@"en-GB": @1600,
@"en-NZ": @0,
@"en-US": @0,
@"fr-FR": @1500,
@"hi-IN": @1130,
@"ja-JP": @800,
@"pt-BR": @2000,
@"zh-CN": @900,
};
}
+ (NSDateComponents *)getDateParts:(NSDate *)date ofCulture:(NSString*)culture
{
NSNumber* cultureHourOffset = _cultureHourOffset[culture];
NSDateComponents* parts = [_gregorian componentsInTimeZone:_TZ_PST fromDate:date];
NSInteger hourOffset = parts.hour * 100 + parts.minute;
if (hourOffset < cultureHourOffset.integerValue)
{
NSDate* pivotDate = [_gregorian dateByAddingUnit:NSCalendarUnitDay
value:-1
toDate:parts.date
options:0];
parts = [_gregorian componentsInTimeZone:_TZ_PST fromDate:pivotDate];
}
return parts;
}
@end