Memory Leak according to Instruments - iphone

Been running instruments on my app. Its says i am leaking 864bytes & 624bytes from 2 NSCFString and the library responsible is Foundation.
So that leads me to believe thats its not a leak caused by me? Or is it?
Here is the offending method according to instruments. It seems to be a
substringWithRange
that is leaking.
-(void) loadDeckData
{
deckArray =[[NSMutableArray alloc] init];
NSString* path = [[NSBundle mainBundle] pathForResource:#"rugby" ofType:#"txt"
inDirectory:#""];
NSString* data = [NSString stringWithContentsOfFile:path encoding:
NSUTF8StringEncoding error: NULL];
NSString *newString = #"";
NSString *newline = #"\n";
NSString *comma = #",";
int commaCount = 0;
int rangeCount = 0;
NSString *nameHolder = #"";
NSString *infoHolder = #"";
NSMutableArray *statsHolder = [[NSMutableArray alloc] init];
for (int i=0; i<data.length; i++)
{
newString = [data substringWithRange:NSMakeRange(i, 1)];
if ([newString isEqualToString: comma]) //if we find a comma
{
if (commaCount == 0)// if it was the first comma we are parsing the
NAME
{
nameHolder = [data substringWithRange:NSMakeRange(i-
rangeCount, rangeCount)];
}
else if (commaCount == 1)//
{
infoHolder = [data substringWithRange:NSMakeRange(i-
rangeCount, rangeCount)];
//NSLog(infoHolder);
}
else // if we are on to 2nd,3rd,nth comma we are parsing stats
{
NSInteger theValue = [[data
substringWithRange:NSMakeRange(i-rangeCount,rangeCount)]
integerValue];
NSNumber* boxedValue = [NSNumber
numberWithInteger:theValue];
[statsHolder addObject:boxedValue];
}
rangeCount=0;
commaCount++;
}
else if ([newString isEqualToString: newline])
{
NSInteger theValue = [[data substringWithRange:NSMakeRange(i-
rangeCount,rangeCount)] integerValue];
NSNumber* boxedValue = [NSNumber numberWithInteger:theValue];
[statsHolder addObject:boxedValue];
commaCount=0;
rangeCount=0;
Card *myCard = [[Card alloc] init];
myCard.name = nameHolder;
myCard.information = infoHolder;
for (int x = 0; x < [statsHolder count]; x++)
{
[myCard.statsArray addObject:[statsHolder
objectAtIndex:x]];
}
[deckArray addObject:myCard];
[myCard autorelease];
[statsHolder removeAllObjects];
}
else
{
rangeCount++;
}
}
[statsHolder autorelease];
}
Thanks for your advice.
-Code

As Gary's comment suggests this is very difficult to diagnose based on your question.
It's almost certainly a leak caused by you however, I'm afraid.
If you go to the View menu you can open the Extended Detail. This should allow you to view a stack trace of exactly where the leak occurred. This should help diagnose the problem.

When to release deckArray? If deckArray is a class member variable and not nil, should it be released before allocate and initialize memory space?

Related

Tread 9: EXC_BAD_ACCESS [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I get this message "Tread 9: EXC_BAD_ACCESS (code=1, address=0x70000010) in this method (but this bug is being created only when in another thread file is being downloaded ):
- (NSMutableDictionary *) getDictionaryAllStatin:(sqlite3*)database
{
if (self._streetsArrey == nil || self._streetsArrey.count <= 0) {
[self getArrayAllStatin:database];
}
/*--------------------------------------------------------------*/
NSMutableDictionary *result1 = [[NSMutableDictionary alloc] init];
for (StreetData *street in _streetsArrey) {
NSString * name = [self deleteContractionWithText:street._name];
NSArray * arr = [name componentsSeparatedByString:#" "];
NSMutableArray *arrm = [[NSMutableArray alloc] initWithArray:arr];
arr = nil;
[arrm addObject:name];
for (NSString *txt in arrm) {
int lengthText = txt.length;
for (int i = 2 ; i <= lengthText; i++) {
NSString * key = [txt substringToIndex:i];
key = [key lowercaseString];
NSMutableDictionary *isSet = [result1 objectForKey:[NSNumber numberWithInt:[key hash]]];
if (isSet == nil) {
isSet = [[NSMutableDictionary alloc]init];
}
[isSet setObject:street forKey:[NSNumber numberWithInt:street._streetId]];
[result1 setObject:isSet forKey:[NSNumber numberWithInt:[key hash]]];
isSet = nil;
key = nil;
}
}
}
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
for (id key in result1) {
NSMutableDictionary *dictionary = [result1 objectForKey:key];
NSArray *arr = [dictionary allValues];
[result setObject:arr forKey:key];
arr = nil;
[dictionary removeAllObjects];
dictionary = nil;
}
[result1 removeAllObjects];
result1 = nil;
/*--------------------------------------------------------------*/
if (result.count > 0) {
_streetsDictionary = result;
result = nil;
return _streetsDictionary;
}else {
_streetsDictionary = nil;
return nil;
}
}
Why do I get this message?
How can I fix it?
The most likely cause for the crash is trying to access an object that has already been deallocated.
Since it seems that the failure arises on the line:
NSMutableDictionary *isSet = [result1 objectForKey:[NSNumber numberWithInt:[key hash]]];
I would suggest splitting the statement down to its component to try and track down which object could actually be the culprit:
NSInteger h = [key hash];
NSNumber n = [NSNumber numberWithInt:h];
...
but this bug is being created only when in another thread file is being downloaded
Also, check if the downloading code and the crashing code have anything in common. The former might be causing the deallocation of an object used in the second.
Hope it helps.

How to display x raise to y in UIlabel

how can I display 5 raise to 1/3 in iphone i.e I want 1/3 written above 5 can anyone help please
I Found this solution, hope so it would be helpful for you.
x to the power of y in a UILabel could be easy. Just replace your indices with unicode superscript characters... I use the following method to turn an integer into a string with superscript characters.
+(NSString *)convertIntToSuperscript:(int)i
{
NSArray *array = [[NSArray alloc] initWithObjects:#"⁰", #"¹", #"²", #"³", #"⁴", #"⁵", #"⁶", #"⁷", #"⁸", #"⁹", nil];
if (i >= 0 && i <= 9) {
NSString *myString = [NSString stringWithFormat:#"%#", [array objectAtIndex:i]];
[array release];
return myString;
}
else {
NSString *base = [NSString stringWithFormat:#"%i", i];
NSMutableString *newString = [[NSMutableString alloc] init];
for (int b = 0; b<[base length]; b++) {
int temp = [[base substringWithRange:NSMakeRange(b, 1)] intValue];
[newString appendString:[array objectAtIndex:temp]];
}
[array release];
NSString *returnString = [NSString stringWithString:newString];
[newString release];
return returnString;
}
}
Try this NSString *cmsquare=#"cm\u00B2";
It will display cm².
Yes you can do that but you need custom UILabel, either Make it by yourself or Get it Open Source..

execute addObject, but NSMutableArray has no object

I try to use to codes below to add object to NSMutableArray
NSMutableArray* multipartData;
- (void)processDataChunk:(NSData *)postDataChunk
{
if (!postHeaderOK)
{
UInt16 separatorBytes = 0x0A0D;
NSData* separatorData = [NSData dataWithBytes:&separatorBytes length:2];
for (int i = 0; i < [postDataChunk length] - l; i++)
{
NSRange searchRange = {i, l};
if ([[postDataChunk subdataWithRange:searchRange] isEqualToData:separatorData])
{
NSRange newDataRange = {dataStartIndex, i - dataStartIndex};
dataStartIndex = i + l;
i += l - 1;
NSData *newData = [postDataChunk subdataWithRange:newDataRange];
if ([newData length])
{
[multipartData addObject:newData]; //A:set break point here
}
}
}
}
}
I set breakpoint at A:, and found that newData is not nil.
What is wrong with my codes?
Welcome any comment
You declare multipartData but do not allocate or initialize it. Somewhere before adding objects you must have
NSMutableArray *multipartData = [[NSMutableArray alloc] init];
or possibly
NSMutableArray *multipartData = [[[NSMutableArray alloc] init] autorelease];
as your needs dictate. But you must allocate and initialize multipartData before adding to or accessing anything in it.

How to solve Memory leaks for following Sqlite code?

I am getting memory leaks in Instruments in the following Sqlite Code.
NSArray *result = [self executeQuery:sql arguments:argsArray];
It calls following method.
- (NSArray *)executeQuery:(NSString *)sql arguments:(NSArray *)args {
sqlite3_stmt *sqlStmt;
if (![self prepareSql:sql inStatament:(&sqlStmt)])
return nil;
int i = 0;
int queryParamCount = sqlite3_bind_parameter_count(sqlStmt);
while (i++ < queryParamCount)
[self bindObject:[args objectAtIndex:(i - 1)] toColumn:i inStatament:sqlStmt];
NSMutableArray *arrayList = [[NSMutableArray alloc] init];
int columnCount = sqlite3_column_count(sqlStmt);
while ([self hasData:sqlStmt]) {
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
for (i = 0; i < columnCount; ++i) {
id columnName = [self columnName:sqlStmt columnIndex:i];
id columnData = [self columnData:sqlStmt columnIndex:i];
[dictionary setObject:columnData forKey:columnName];
}
[arrayList addObject:[dictionary autorelease]];
}
sqlite3_finalize(sqlStmt);
return arrayList;
}
How do I solve it ?
We'd need to see the code of your executeQuery method - it should be returning an auto-released result, but perhaps it isn't.
You could try ;
NSArray *result = [[self executeQuery:sql arguments:argsArray] autorelease];
But I'd be wary of just blindly trying that without actually seeing what executeQuery does in detail.
EDIT:
OK, here's your problem;
NSMutableArray *arrayList = [[NSMutableArray alloc] init];
Either create it as an auto-released array, or finish the method with;
return [arrayList autorelease];

Creating a long NSString causing memory issues

My code below is causing my app to quit i.e. get black screen and then see in debugger console: Program received signal: “0”.
Basically it is causing problem when my orderArray has count of 2000 or more. I am using iPhone 3GS with iOS 4.2
Question: Is there a more efficient and less memory consuming way to create my long outStr?
NSString *outStr = #"";
for (int i = 0; i < count; i++) {
NSDictionary *dict = [[ARAppDelegate sharedAppDelegate].orderArray objectAtIndex:i];
outStr = [outStr stringByAppendingFormat:#"%#,%#,%#,%#\n",
[dict valueForKey:#"CODE"],
[dict valueForKey:#"QTY"],
[[ARAppDelegate sharedAppDelegate].descDict valueForKey:[dict valueForKey:#"CODE"]],
[[ARAppDelegate sharedAppDelegate].priceDict valueForKey:[dict valueForKey:#"CODE"]]];
}
Update: Thanks to very kind people who helped, below is my modified code:
NSArray *orderA = [ARAppDelegate sharedAppDelegate].orderArray;
NSDictionary *descD = [ARAppDelegate sharedAppDelegate].descDict;
NSDictionary *priceD = [ARAppDelegate sharedAppDelegate].priceDict;
NSMutableString *outStr = [[[NSMutableString alloc] init] autorelease];
for (int i = 0; i < [orderA count]; i++) {
NSDictionary *dict = [orderA objectAtIndex:i];
NSString *code = [dict valueForKey:#"CODE"];
[outStr appendFormat:#"%#,%#,%#,%#\n",
code,
[dict valueForKey:#"QTY"],
[descD valueForKey:code],
[priceD valueForKey:code]];
}
[self emailTxtFile:[NSString stringWithString:outStr]];
// This reaches end of method
The problem is that in every iteration a new string object is formed. This consumes a lot of memory. One solution could be to use a local autoreleasepool, but that's rather complicated here.
You should use an NSMutableString, like:
NSMutableString *outStr = [[[NSMutableString alloc] init] autorelease];
for (int i = 0; i < count; i++) {
NSDictionary *dict = [[ARAppDelegate sharedAppDelegate].orderArray objectAtIndex:i];
[outStr appendFormat:#"%#,%#,%#,%#\n",
[dict valueForKey:#"CODE"],
[dict valueForKey:#"QTY"],
[[ARAppDelegate sharedAppDelegate].descDict valueForKey:[dict valueForKey:#"CODE"]],
[[ARAppDelegate sharedAppDelegate].priceDict valueForKey:[dict valueForKey:#"CODE"]]];
}
Then you can use outStr, just as if it was an NSString. As Tom points out in the comments, you could turn the NSMutableString into an NSString when you're finished, using:
NSString *result = [NSString stringWithString:outStr];
[outStr release]; // <-- add this line and remove the autorelease
// from the outStr alloc/init line
making your code re-usable and easier to maintain.