NSMutableArray memory leak when reloading objects - ios

I am using Three20/TTThumbsviewcontroller to load photos. I am struggling since quite a some time now to fix memory leak in setting photosource. I am beginner in Object C & iOS memory management. Please have a look at following code and suggest any obvious mistakes or any errors in declaring and releasing variables.
-- PhotoViewController.h
#interface PhotoViewController : TTThumbsViewController <UIPopoverControllerDelegate,CategoryPickerDelegate,FilterPickerDelegate,UISearchBarDelegate>{
......
NSMutableArray *_photoList;
......
#property(nonatomic,retain) NSMutableArray *photoList;
-- PhotoViewController.m
#implementation PhotoViewController
....
#synthesize photoList;
.....
- (void)LoadPhotoSource:(NSString *)query:(NSString *)title:(NSString* )stoneName{
NSLog(#"log- in loadPhotosource method");
if (photoList == nil)
photoList = [[NSMutableArray alloc] init ];
[photoList removeAllObjects];
#try {
sqlite3 *db;
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *dbPath = [documentsPath stringByAppendingPathComponent: #"DB.s3db"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured.");
}
NSString *_sql = query;
const char *sql = [_sql UTF8String];
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement");
}
if ([stoneName length] != 0)
{
NSString *wildcardSearch = [NSString stringWithFormat:#"%#%%",[stoneName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
sqlite3_bind_text(sqlStatement, 1, [wildcardSearch UTF8String], -1, SQLITE_STATIC);
}
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
NSString* urlSmallImage = #"Mahallati_NoImage.png";
NSString* urlThumbImage = #"Mahallati_NoImage.png";
NSString *designNo = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,2)];
designNo = [designNo stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *desc = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,7)];
desc = [desc stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *caption = designNo;//[designNo stringByAppendingString:desc];
caption = [caption stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *smallFilePath = [documentsPath stringByAppendingPathComponent: [NSString stringWithFormat:#"Small%#.JPG",designNo] ];
smallFilePath = [smallFilePath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([fileMgr fileExistsAtPath:smallFilePath]){
urlSmallImage = [NSString stringWithFormat:#"Small%#.JPG",designNo];
}
NSString *thumbFilePath = [documentsPath stringByAppendingPathComponent: [NSString stringWithFormat:#"Thumb%#.JPG",designNo] ];
thumbFilePath = [thumbFilePath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([fileMgr fileExistsAtPath:thumbFilePath]){
urlThumbImage = [NSString stringWithFormat:#"Thumb%#.JPG",designNo];
}
NSNumber *photoProductId = [NSNumber numberWithInt:(int)sqlite3_column_int(sqlStatement, 0)];
NSNumber *photoPrice = [NSNumber numberWithInt:(int)sqlite3_column_int(sqlStatement, 6)];
char *productNo1 = sqlite3_column_text(sqlStatement, 3);
NSString* productNo;
if (productNo1 == NULL)
productNo = nil;
else
productNo = [NSString stringWithUTF8String:productNo1];
Photo *jphoto = [[[Photo alloc] initWithCaption:caption
urlLarge:[NSString stringWithFormat:#"documents://%#",urlSmallImage]
urlSmall:[NSString stringWithFormat:#"documents://%#",urlSmallImage]
urlThumb:[NSString stringWithFormat:#"documents://%#",urlThumbImage]
size:CGSizeMake(123, 123)
productId:photoProductId
price:photoPrice
description:desc
designNo:designNo
productNo:productNo
] autorelease];
[photoList addObject:jphoto];
[jphoto release];
}
}
#catch (NSException *exception) {
NSLog(#"An exception occured: %#", [exception reason]);
}
self.photoSource = [[[MockPhotoSource alloc]
initWithType:MockPhotoSourceNormal
title:[NSString stringWithFormat: #"%#",title]
photos: photoList
photos2:nil] autorelease];
}
Memory leaks happen when calling above LoadPhotosource method again with different query...
I feel its something wrong in declaring NSMutableArray (photoList), but can't figure out how to fix memory leak.
Any suggestion is really appreciated.

I havent seen any leaked objects in your code, but actually a double released object that will eventually crash your app:
In your last lines, you have this:
Photo *jphoto = [[[Photo alloc] initWithCaption:caption
urlLarge:[NSString stringWithFormat:#"documents://%#",urlSmallImage]
urlSmall:[NSString stringWithFormat:#"documents://%#",urlSmallImage]
urlThumb:[NSString stringWithFormat:#"documents://%#",urlThumbImage]
size:CGSizeMake(123, 123)
productId:photoProductId
price:photoPrice
description:desc
designNo:designNo
productNo:productNo
] autorelease];
[photoList addObject:jphoto];
[jphoto release];
If you take a closer look, you have a double release (autorelease in alloc and release after the addObject). You should remove one of them.
Besides that, I would also recommend you a few things:
Switch to ARC: If you are new, you will definetly take advantage of it because you will not have to worry about almost any of the memory management anymore. Your code will be free of leaked objects and memory crashes. Just be careful with the memory retain cycles and with variable ownerships and you are done.
Remove NSMutableArray *_photoList;, you are not using it since you declare your property syntetizer as #synthesize photoList;. In addition, as Robert commented below, you should use this form to clearly differentiate when you use the property:
#synthesize photoList = photoList_;
The underscore is better at the end because Apple uses it at the beginning and you dont want to accidentally use the same variable name.
Use property accessors to manage ivars. Instead of doing this:
if (photoList == nil)
photoList = [[NSMutableArray alloc] init ];
try this:
if (photoList == nil)
self.photoList = [[[NSMutableArray alloc] init] autorelease];
In your example both lines have the same behaviour, but the second one is preferable because it will rely on your variable memory policy. If you change your retain by a copy or an assign one day, your code will still work without any problem. In the same way, release your memory by assigning your ivar a nil like this self.photoList = nil
Why do you think you have a leaked object?

Just to recap on my observations:
I don't think it's related, but I think you want #synthesize photoList = _photoList. Right now, you have two ivars, the one you declared explicitly, _photoList, and one that is created implicitly from your photoList property, photoList. I'd also get rid of the existing explicit declaration of the _photoList ivar, as Apple current advises that you let the synthesize statement do that for you. (And it prevents situations like this, where you ended up with additional ivars accidentally.)
Also, again unrelated to a leak (but rather the converse problem), but jphoto is being over released, because you're issuing both an autorelease as well as a release. The latter is sufficient.
Also, I don't see your sqlite3_finalize() and sqlite3_close() statements. Where are they? According to the docs, "Every prepared statement must be destroyed using a call to [sqlite3_finalize()] in order to avoid memory leaks."
Finally, if you still have a leak after adding the finalize/close statements for your database, I'd suggest running your code through the leaks tool in the profiler to find the leak. This will help you identify precisely what's leaking.

Related

Potential leaks in iOS project

Hello i have this function, that gets dummy data from file in project:
Issues are shown in those lines:
NSString *path = [[NSBundle mainBundle] pathForResource: #"StatisticsDataJSON" ofType: #"TXT"]; - potential leak of an object.
NSMutableDictionary *statisticsResponse = [jsonParser objectWithString:data]; - potential leak of an object stored into 'jsonParser'
for (id key in statisticsResponse) { - potential leak of an object stored into 'statisticArray'
for (int i = 0; i < statsForDate.count; i++) { - potential leak of an object stored into 's'
if (self.statistics==nil)
{
self.statistics = [[NSMutableDictionary alloc]init];
NSString *path = [[NSBundle mainBundle] pathForResource: #"StatisticsDataJSON" ofType: #"TXT"];
NSError *error = nil;
NSString *data = [NSString stringWithContentsOfFile: path
encoding: NSUTF8StringEncoding
error: &error];
//NSLog(#"%#",data);
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSMutableDictionary *statisticsResponse = [jsonParser objectWithString:data];
for (id key in statisticsResponse) {
NSArray *statsForDate = [statisticsResponse objectForKey:key];
NSMutableArray *statisticArray = [[NSMutableArray alloc]init];
for (int i = 0; i < statsForDate.count; i++) {
Statistic *s = [[Statistic alloc]init];
s.locationId = [[statsForDate objectAtIndex:i] objectForKey:#"locationId"];
int value =[[[statsForDate objectAtIndex:i] objectForKey:#"visits"] integerValue];
s.visits = value;
value =[[[statsForDate objectAtIndex:i] objectForKey:#"totalUsers"] integerValue];
s.totalUsers = value;
value= [[[statsForDate objectAtIndex:i] objectForKey:#"uploads"] integerValue];
s.uploads = value;
value = [[[statsForDate objectAtIndex:i] objectForKey:#"downloads"] integerValue];
s.downloads = value;
value = [[[statsForDate objectAtIndex:i] objectForKey:#"apps"] integerValue];
s.apps = value;
[statisticArray addObject:s];
}
[self.statistics setObject:statisticArray forKey:key];
};
}
I have found that autorelease in ststisticsResponse - resolves the problem:
NSMutableDictionary *statisticsResponse = [[jsonParser objectWithString:data]autorelease];
But then something fails in SBJsonStreamParserAccumulator.m in dealoc function.
What is the problem?
Note that the warnings about potential leaks come on the line after the potential leak, because that's the first point at which the referenced object is technically "leaked". So your current fixes are probably over-releasing and causing crashes.
The first statement in your question actually refers to a leak in this line, immediately before:
self.statistics = [[NSMutableDictionary alloc]init];
You've got no further reference to that allocated dictionary, and it's a retained property, so you have a leak.
self.statistics = [[[NSMutableDictionary alloc]init] autorelease];
Will fix that one. The next one, you have to release the jsonParser when you've finished with it (after the parsing is done):
[jsonParser release];
I'm not going to go through all of them but you should get the idea. Basically you need to read the memory management guide, or update to ARC.
Pay attention to the variable names in the warnings. They tell you where the leak is.

Insert statement does not work (even in the copied db at Documents folder)

First of all I'm new here, so i would like to thank the community which is helping me a lot in my projects.
I'm actually working on an application which have to provide customers information from local sqlite db.
I did the following :
I copy the sqlite database (if no db exist in document folder) when the application is launched
When the user is asking for update in the interface, a method is called and fill the customer_information table in the database.
When the user is going back to the main screen, a method is called and refresh information displaying according to values in the sqlite database.
The problem is that no values are displaying. XCode can't found any errors in my code and even if I tried many different way for inserting values, I can't find where is the issue.
Thank you in advance and sorry about my bad english, I'm French.
Sincerely.
Please find following extracts from my source code, you have any question don't hesitate :
Copying the db in documents folder
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSError *emsg;
BOOL fileExist;
//Get list of directories in Document path
NSArray *dirPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//Define new path for database
NSString *documentPath = [[dirPath objectAtIndex:0] stringByAppendingPathComponent:#"Vidagen_ios.sqlite"];
// Path of db in the application
NSString *origin = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Vidagen_ios.sqlite"];
fileExist = [[NSFileManager defaultManager] fileExistsAtPath:documentPath];
if(!fileExist){
[[NSFileManager defaultManager] copyItemAtPath:origin toPath:documentPath error:&emsg];
NSLog(#"db copied");
}
// Override point for customization after application launch.
return YES;
}
Update method
- (void)insertRecords
{
sqlite3_stmt *sqlStatement = nil;
sqlite3 *newDb;
// Request
const char *sql = "INSERT INTO client_information(client_info_id, client_info_name, client_info_sex, client_info_age, client_info_id_card, client_info_tel, client_info_tall, client_info_weight, client_info_address, client_info_email, client_info_pwd, client_info_client_source_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)";
// Path of copied db
NSArray *dirPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *database = [[dirPath objectAtIndex:0] stringByAppendingPathComponent:#"Vidagen_ios.sqlite"];
// db sequence
if(sqlite3_open([database UTF8String], &newDb) == SQLITE_OK){
NSLog(#"ouverture de la base ok");
for (int i=0; i<11; i++) {
sqlite3_bind_text(sqlStatement, i, [[NSString stringWithFormat:#"Test"] UTF8String], -1, SQLITE_TRANSIENT);
}
sqlite3_bind_int(sqlStatement, 11, 1);
sqlite3_prepare_v2(newDb, sql, 1, &sqlStatement, NULL);
if (sqlite3_step(sqlStatement) == SQLITE_OK) {
NSLog(#"client ajouté");
} else{
NSLog(#"Echec d'ajout");
}
sqlite3_step(sqlStatement);
sqlite3_finalize(sqlStatement);
sqlite3_close(newDb);
};
}
Here's i noticed that the step is different than "SQLITE_OK".
Method displaying the information
- (void)viewDidLoad
{
infoCustomer = [[CustomerDAO alloc] init];
if([[infoCustomer getCurrentCustomer] count] > 0){
self.customer = [[infoCustomer getCurrentCustomer] objectAtIndex:0];
[self.uniqueId setText:self.customer.uniqueId];
[self.name setText:self.customer.name];
[self.sex setText:self.customer.sex];
[self.tall setText:self.customer.tall];
[self.weight setText:self.customer.weight];
[self.age setText:self.customer.age];
[self.address setText:self.customer.address];
[self.tel setText:self.customer.tel];
[self.email setText:self.customer.email];
} else{
NSLog(#"customer not read");
[self.uniqueId setText:#"Go to Update."];
[self.name setText:#""];
[self.sex setText:#""];
[self.tall setText:#""];
[self.weight setText:#""];
[self.age setText:#""];
[self.address setText:#""];
[self.tel setText:#""];
[self.email setText:#""];
}
[super viewDidLoad];
// Do any additional setup after loading the view.
}
EDIT :
I continued my research since yesterday and though something wrong in
my source code :
sqlite3_prepare_v2(newDb, sql, 1, &sqlStatement, NULL);
The third parameter have to be change to -1 since it's defining the
length of my request. I used some tutorials for learning sqlite
request and I didn't really spend time to understand all the
parameters I saw. If you define it as -1 that's means the length will
be auto-calculated at the runtime.
I feel frustrated to loose so many time on such mistake, it shown to
me how it is hard to work with no enough experience or no external
opinion.

iOS - App crash without error during loop process

during a loop process, my App crash without error. The array count is equal to 175260. With profiler I don't have leaks, so I don't know why the App exit, maybe the CPU usage 100% during a lot of time?
Thank you for your help.
Just this code following crash the App :
for(unsigned int i = 0; i <14;i++)
{
if(findSensor[i]==YES)
{
for(unsigned int j = 1; j <[array count];j++)
{
#autoreleasepool {
if([[[[array objectAtIndex:j] componentsSeparatedByString:#";"] objectAtIndex:0] isEqualToString:[NSString stringWithFormat:#"%d",10*(i+1)]])
{
//Code here
}
}
}
}
}
The full code is :
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fileName = [NSString stringWithFormat:#"%#/%#",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase];
NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:fileName];
NSFileHandle *output = [NSFileHandle fileHandleForReadingAtPath:[NSString stringWithFormat:#"%#/%#10",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase]];
if(output == nil)
{
NSManagedObjectContext *context = [self managedObjectContext];
_recordlocal = [NSEntityDescription insertNewObjectForEntityForName:#"RECORD" inManagedObjectContext:context];
_recordlocal.date = [ibNavSettings interfaceSettings].selectedFileToDataBase;
NSData *inputData = [NSData dataWithData:[fh readDataToEndOfFile]];
NSString *inputString = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding];
NSArray *array = [[NSArray alloc] initWithArray:[inputString componentsSeparatedByString:#"\n"]];
for(unsigned int i = 0; i <14;i++)
{
if(findSensor[i]==YES)
{
[[NSFileManager defaultManager] createFileAtPath:[NSString stringWithFormat:#"%#/%#%d",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase,10*(i+1)] contents:nil attributes:nil];
NSMutableString *saveString = [[NSMutableString alloc] init];
int count = 0;
for(unsigned int j = 1; j <[array count];j++)
{
#autoreleasepool {
if([[[[array objectAtIndex:j] componentsSeparatedByString:#";"] objectAtIndex:0] isEqualToString:[NSString stringWithFormat:#"%d",10*(i+1)]])
{
[saveString appendString:[array objectAtIndex:j]];
[saveString appendString:#"\n"];
if(i == 0)
count++;
progress++;
pourcent = progress/total;
load = pourcent*100;
if(load%5==0)
[self performSelectorInBackground:#selector(changeUI:)withObject:[NSNumber numberWithFloat:(pourcent)]];
}
}
}
[saveString writeToFile:[NSString stringWithFormat:#"%#/%#%d",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase,10*(i+1)] atomically:YES encoding:NSUTF8StringEncoding error:nil];
if(i == 0)
_recordlocal.count = [[NSNumber alloc] initWithInt:(count/50)];
}
}
_recordlocal.load = [[NSNumber alloc] initWithBool:YES];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Core data error %#, %#", error, [error userInfo]);
abort();
}
I would guess that your app is crashing without a readable exception because it is running out of available RAM, especially since you indicated that it is running through a large number of iterations.
For a test, I would recommend doing what Rikkles suggests with the autorelease pool. In addition, since the value of i (and as a result the comparison string) rarely changes, I would create that string outside the j loop as well. This would avoid the creation of a lot of extra strings laying around.
Beyond that, since it appears that you are looking for a string at the beginning of a string that is delimited by a semicolon, I would recommend instead of doing componentsSeparatedByString and then examining element zero that you use the NSString method hasPrefix to check for the condition you are looking for.
Here is an example:
for(unsigned int i = 0; i <14;i++)
{
NSString *searchString = [NSString stringWithFormat:#"%d;", 10*(i+1)];
if(findSensor[i]==YES)
{
for(unsigned int j = 1; j <[array count];j++)
{
if([[array objectAtIndex:j] hasPrefix:searchString])
{
//Code here
}
}
}
}
(I hope this compiles and runs, if it doesn't it should require more than minor tweaks. I am away from my Mac right now.)
If this doesn't help, then something going on inside //Code here must be the culprit.
Why are you creating [array count] autoreleasepools? What's the point of creating so many of them? It could crash because of that. Put the #autoreleasepool outside the for loop.
The only reason I could think that you would do that is if you create so many transient objects inside each iteration of the for loop that you'd want to get rid of them as soon as you got out of the iteration. But there are other ways to do that, including reusing those objects within each iteration.
First suggestion
Just use fast enumeration for the inner loop, you aren't actually using the index 'j' for anything
https://developer.apple.com/library/mac/documentation/General/Conceptual/DevPedia-CocoaCore/Enumeration.html
Second suggestion
Put some NSLog's in place, it will slow everything down, but you need to figure out what point you are failing at. That will help point everyone in the right direction.
Third suggestion
Actually use NSError objects and output their value if an error is thrown:
NSError *writeError = nil;
[saveString writeToFile:[NSString stringWithFormat:#"%#/%#%d",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase,10*(i+1)]
atomically:YES
encoding:NSUTF8StringEncoding
error:&writeError];
if(error != nil) NSLog(#"error writing file: %#", [[writeError userInfo]description]);
Fourth suggestion
You appear to try to be updating the UI from a background thread. This will not work or will cause a crash. UI code can only be called from a main thread. So dont do this:
[self performSelectorInBackground:#selector(changeUI:)withObject:[NSNumber numberWithFloat:(pourcent)]];
If you are already on a background thread this will probably crash because you are creating threads on threads on threads. You instead would want to call:
[self performSelectorOnMainThread:#selector(changeUI:)withObject:[NSNumber numberWithFloat:(pourcent)]];
Fifth suggestion
You may be going over the maximum length for NSString (it's big but I did it once on accident before). You should probably just be appending the file on each iteration of the loop instead, so you don't have an ever growing NSMutableString:
NSString *path = [NSString stringWithFormat:#"%#/%#%d",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase,10*(i+1)]
NSFileHandle *fh = [NSFileHandle fileHandleForWritingAtPath:filePath];
NSData *newLine = [#"\n" dataUsingEncoding:NSUTF8StringEncoding];
for(NSString *rowString in array)
{
if([[[rowString componentsSeparatedByString:#";"] objectAtIndex:0] isEqualToString:[NSString stringWithFormat:#"%d",10*(i+1)]])
{
NSData *stringData = [rowString dataUsingEncoding:NSUTF8StringEncoding];
[fh truncateFileAtOffset:[fh seekToEndOfFile]];
[fh writeData:stringData];
[fh truncateFileAtOffset:[fh seekToEndOfFile]];
[fh writeData:newLine];
if(i == 0)
count++;
progress++;
pourcent = progress/total;
load = pourcent*100;
if(load%5==0)
[self performSelectorOnMainThread:#selector(changeUI:)withObject:[NSNumber numberWithFloat:(pourcent)]];
}
}
}
And this has the added benefit of helping you ditch the autoreleasepools
This was invalid
If your array does in fact have 175260 rows, that is probably your issue. You are looping using unsigned int as your index var. Unsigned ints in c only have a max value of 65535. Use an unsigned long int, max 4294967295.

EXC_BAD_ACCESS and stringByAppendingString

Getting EXC_BAD_ACCESS when setting a label with the value returned by the following function defined in a class called DataHelper (all database handling done here):
+(NSString *)getCurrentBalanceAndType:(NSString *)account
{
sqlite3_stmt *statement=NULL;
float bal=0;
NSString *type=NULL, *balance_type=NULL;
//String decimalFormat="%.2f";
statement = [DataHelper getDetailsFromAccountBal:account:[DataHelper currentMonth]];
if (sqlite3_step(statement) == SQLITE_ROW)
{
bal = sqlite3_column_double(statement,2);
type = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
}
sqlite3_finalize(statement);
NSString *stringBal=[NSString stringWithFormat:#"%.2f", bal];
type=[[type uppercaseString] stringByAppendingString:#"r"];
balance_type=[[stringBal stringByAppendingString:#" "]stringByAppendingString:type];
[type release];
return balance_type;
}
This is how I am setting the label in viewDidLoad:
lbCreditCurrBal.text=[DataHelper getCurrentBalanceAndType:#"Some Text"];
Please help.
You are overreleasing type. Remove [type release];. And use ARC to avoid this kind of errors.
When you call a method that begins with anything except init or copy, you’re returned an object that will be autoreleased at some point in the future.
reference- ray's memory management blog
keeping above in mind I think you should not release the type object as said by Nikolai.

iOS Memory Management & NSString Initialisation

Still learning iOS development with ObjectiveC and iOS, and trying to realy understand memory management! Appreciate any advise on the snippet below, eg:
1) Analyser says there are potential memory leaks, but can't solve them?
2) Should I keep alloc and init the NSStrings in the for loop and when appended to?
Thanks
- (NSString *) lookUpCharNameForID: (NSString *) inCharID
{
debugPrint ("TRACE", [[#"Lookup Char Name for = " stringByAppendingString: inCharID] UTF8String]);
NSString *tempName = [[NSString alloc] initWithFormat: #""];
if (![inCharID isEqualToString: #""])
{
// Potentially lookup multiple values
//
NSString *newName = [[NSString alloc] initWithFormat: #""];
NSArray *idList = [inCharID componentsSeparatedByString: #","];
for (NSString *nextID in idList)
{
NSLog( #"Lookup %i : %#", [idList count], nextID);
newName = [[NSString alloc] initWithFormat: #"C%#", nextID];
// Append strings
if ([tempName isEqualToString: #""])
tempName = [[NSString alloc] initWithFormat: #"%#", newName];
else
tempName = [[NSString alloc] initWithFormat: #"%#+%#", tempName, newName];
}
[newName release];
}
return [tempName autorelease];
}
You don't need any of the calls to alloc, release, or autorelease. Instead, use [NSString stringWithFormat:] to create instances of NSString that you don't own, and therefore don't need to manage. Also, consider using NSMutableString to simplify your code a bit, for example along the lines of the following (untested) version:
- (NSString *) lookUpCharNameForID: (NSString *) inCharID
{
NSMutableString *tempName = nil;
if (![inCharID isEqualToString: #""])
{
NSArray *idList = [inCharID componentsSeparatedByString: #","];
for (NSString *nextID in idList)
{
[tempName appendString:#"+"]; // Does nothing if tempName is nil.
if (tempName == nil)
tempName = [NSMutableString string];
[tempName appendFormat:#"C%#", nextID];
}
}
return tempName;
}
You have 2 alloc initWithFormat for tempName. One before the loop and one within the loop.
Use ARC (Automatic Reference Counting) for new projects. For older projects it may be easy to convert them, if not ARC can be disabled on a file-by-file basis where necessary.
Using a mutable string, autoreleased convience methods and a little rerfactoring:
- (NSString *) lookUpCharNameForID: (NSString *) inCharID
{
NSMutableString *tempName = [NSMutableArray array];
if (inCharID.length)
{
NSArray *idList = [inCharID componentsSeparatedByString: #","];
for (NSString *nextID in idList)
{
if (tempName.length == 0)
[tempName appendFormat: #"%#C", nextID];
else
[tempName appendFormat: #"+%#C", nextID];
}
}
return tempName;
}

Resources