问题
I have a problem with NSDateFormatter dateFromString:
method. There is an array of dictionaries with string dates and I want to convert them to NSDates
. But there is a huge heap growth every time I call this method (I need to call it more than once, cause it's an "update" method). Also I call it in background thread and ARC is on. What am I doing wrong? Any help, please.


UPDATE: Full code of the function:
- (GraphController *) initGraphWithData: (NSArray *) points forInterval: (GraphInterval) interval andFrame: (CGRect) frame gestures: (BOOL) gestures secondGraph: (NSArray *) secondPoints graphNames: (NSArray *) graphNames
{
self = [super init];
_calendar = [NSCalendar currentCalendar];
_secondPoints = secondPoints;
_graphNames = graphNames;
[self.view setFrame:frame];
_points = [[NSMutableArray alloc] init];
double minValue = HUGE_VALF, maxValue = -HUGE_VALF;
NSDate *minDate = [NSDate date], *maxDate = [NSDate dateWithTimeIntervalSince1970:0];
NSMutableDictionary *datesTable = [[NSMutableDictionary alloc] init];
int index = 0;
for(NSArray *pointArray in points){
NSDictionary *point = pointArray[0];
NSMutableDictionary *newPoint = [[NSMutableDictionary alloc] initWithDictionary:point];
// convert date
NSString *dateString = (NSString *)[point objectForKey:@"date"];
NSLog(@"dateString to convert: %@", dateString);
[_dateFormatter setDateFormat:@"MM/dd/yyyy"];
NSDate *date = [_dateFormatter dateFromString: dateString];
[newPoint setObject: date forKey:@"date"];
// convert numbers
[newPoint setObject: [NSNumber numberWithFloat:[((NSString *)[point objectForKey:@"value"]) floatValue]] forKey:@"value"];
if(secondPoints)
[newPoint setObject: [NSNumber numberWithFloat:[((NSString *)[secondPoints[index] objectForKey:@"value"]) floatValue]] forKey:@"secondValue"];
[newPoint setObject: [NSNumber numberWithInt:index] forKey:@"index"];
// min and max
if([[newPoint objectForKey:@"value"] floatValue] < minValue)
minValue = [[newPoint objectForKey:@"value"] floatValue];
if([[newPoint objectForKey:@"value"] floatValue] > maxValue)
maxValue = [[newPoint objectForKey:@"value"] floatValue];
// check second value
if(self.secondPoints){
if([[newPoint objectForKey:@"secondValue"] floatValue] < minValue)
minValue = [[newPoint objectForKey:@"secondValue"] floatValue];
if([[newPoint objectForKey:@"secondValue"] floatValue] > maxValue)
maxValue = [[newPoint objectForKey:@"secondValue"] floatValue];
}
if([[newPoint objectForKey:@"date"] timeIntervalSince1970] > [maxDate timeIntervalSince1970])
maxDate = [newPoint objectForKey:@"date"];
if([[newPoint objectForKey:@"date"] timeIntervalSince1970] < [minDate timeIntervalSince1970])
minDate = [newPoint objectForKey:@"date"];
[self.points addObject:newPoint];
[datesTable setObject:newPoint forKey: [[NSNumber numberWithDouble:[date timeIntervalSince1970]] stringValue] ];
index++;
}
// set draw parameters
_drawVars = [[NSMutableDictionary alloc] init];
NSDate *startSearchDate;
switch (interval) {
case GraphIntervalWeek:
startSearchDate = [maxDate dateByAddingTimeInterval:-7*24*3600];
break;
case GraphIntervalMonth:
startSearchDate = [maxDate dateByAddingTimeInterval: -31*24*3600];
break;
case GraphIntervalSixMonths:
startSearchDate = [maxDate dateByAddingTimeInterval:-6*31*24*3600];
break;
case GraphIntervalYear:
startSearchDate = [maxDate dateByAddingTimeInterval:-365*24*3600];
break;
case GraphIntervalAllTime:
break;
default:
break;
}
NSMutableDictionary *searchPoint;
while(searchPoint == nil && [startSearchDate timeIntervalSince1970] > [minDate timeIntervalSince1970]){
searchPoint = [datesTable objectForKey:[[NSNumber numberWithDouble:[startSearchDate timeIntervalSince1970]] stringValue]];
startSearchDate = [startSearchDate dateByAddingTimeInterval:-24*3600];
}
if(searchPoint != nil && interval != GraphIntervalAllTime)
[self.drawVars setObject:[searchPoint objectForKey:@"index"] forKey:@"startDrawIndex"];
else
[self.drawVars setObject:[NSNumber numberWithInt:0] forKey:@"startDrawIndex"];
[self.drawVars setObject:[[NSNumber numberWithFloat:minValue] copy] forKey:@"minValue"];
[self.drawVars setObject:[[NSNumber numberWithFloat:maxValue] copy] forKey:@"maxValue"];
[self.drawVars setObject:minDate forKey:@"minDate"];
[self.drawVars setObject:maxDate forKey:@"maxDate"];
[self.drawVars setObject:datesTable forKey:@"datesTable"];
// set drawImageView
_drawArea = [[UIImageView alloc] initWithFrame: frame];
[self.view addSubview:self.drawArea];
// set overlayImageView for fingerInpect
_inspectOverlay = [[UIImageView alloc] initWithFrame:frame];
[self.view addSubview:self.inspectOverlay];
// set hintUIView for fingerInspect
_hint = [[Hint alloc] initWithFrame:frame];
[self.hint initHint];
self.hint.hidden = YES;
[self.drawArea addSubview:self.hint];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panHandler:)];
UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressHandler:)];
if(gestures)
[self.view addGestureRecognizer:panRecognizer];
[self.view addGestureRecognizer:longPressRecognizer];
return self;
}
回答1:
I see you are using Heapshot analysis. Good. Here are some more details:
http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/
Now, hopefully, each one of your Heapshot iterations represents doing something in your app that should return it back to the base state. Opening and closing a document, for example.
If that is the case, your data is showing a 500K-600K growth per iteration. That is quite a bit.
Note that trying to analyze the last iteration is generally useless; many of those objects will exist because of whatever the current state of the app is. You really want to focus on that 2nd or 4th iteration.
As for why that specific date or date formatter is leaking, turn on reference count event tracking and then review the retain/release events for one of the leaked objects. There will be some number of extra retains.
回答2:
Something you are doing right is init
the NSDateFormatter
before entering the loop. If you are expecting the same date format (MM/dd/yyyy
) you can put in the same place you init
it as well. It can be that you are allocating too many objects, so I could advise putting everything inside an @autoreleasepool {}
(aka: the content of the loop inside the autorelease).
I am seeing you are allocating the *newPoint
inside the for and then you are setting the date to that object. What do you do after?
来源:https://stackoverflow.com/questions/17765342/nsdateformatter-memory-leak