I have a string which I am updating constantly (~33 times a second). It is used over and over and over again and is omnipresent in a loop I have going. This is the loop:
- (void)add{
int r = (arc4random() % 30) + 51;
long long debtInt = [debtString longLongValue];
long long multiplier = r;
long long debtAdj = multiplier + debtInt;
debtString = [NSString stringWithFormat:@"%lli", debtAdj];
[debtString retain];
[self formating];
}
- (void)formating{
NSNumberForma开发者_StackOverflow中文版tter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * myNumber = [f numberFromString:debtString];
[f release];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setMaximumFractionDigits:0];
NSString *formattedNumberString = [numberFormatter stringFromNumber:myNumber];
[numberFormatter release];
UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 325, 100)];
myLabel.font = [UIFont fontWithName:@"Verdana" size: 20.0];
myLabel.text = formattedNumberString;
myLabel.textAlignment = UITextAlignmentCenter;
[self.view addSubview:myLabel];
[myLabel release];
}
which is fired off by an NSTimer every 0.03 seconds. The one spot where I thought I could logically release the debtString
was after it is converted to a long long integer. This, however, crashes the app. If I remove the [debtString retain]
line, the app crashes.
The memory build up is quick and fast, it is a 14 byte string. Every second that creates another 462 bytes of mis-allocated memory, that along with all the adjustments, comes out to roughly 3696 byes/sec. This is not a leak I can ignore. I just don't know where to release it in the loop!
If you're committed to doing it this way, you should release your debtString
in each iteration of the loop, right before you reassign the value:
[debtString release];
debtString = [NSString stringWithFormat:@"%lli", debtAdj];
[debtString retain];
However, you're creating a new instance every loop. You'd be better served using a single NSMutableString
(like @OscarMk suggested) and updating it each time. And don't create a new UILabel
each time. Just create one and update the contents each time through the loop.
You should be using a NSMutableString specially if it is getting updated that often.
When you use the stringWithNumber: method you get back a string that is in the autorelease pool. These get released when you get back to the event loop.
Instead use explicit alloc and init:
[debtString release]; // release previous (if any)
debtString = [[NSString alloc] initWithFormat:@"%lli", debtAdj];
If debtString is a @property that is retained this is what the setter would do for you.
And highlycaffeinated is right, don't create a new UILabel each time, just update the text field. Same for NSNumberFormatter, save it as in instance variable so you don't have to create it each time (and then you only add it to the subview once).
The issue was I was declaring the variables each time, rather than synthesizing them in the header. Fixed it in ten minutes.
精彩评论