read and write using NSKeyedArchiver, ios - iphone

Below is a class to read and write data using nsarchive
Data.m
-(id)init {
self = [super init];
if(self) {
arr = [[NSMutableArray alloc] init];
}
return self;
}
-(NSString *)getPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath;
if ([paths count] > 0)
documentPath = [paths objectAtIndex:0];
NSString *draftDataPath = [documentPath stringByAppendingPathComponent:#"draftData.dat"];
return draftDataPath;
}
-(void)saveDataToDisk {
NSString *path = [self getPath];
[NSKeyedArchiver archiveRootObject:arr toFile:path];
}
-(void)loadDataFromDisk {
NSString *path = [self getPath];
self.arr = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
}
At later on, I am adding some objects into arr by doing
CustomerClass.m
- (void) viewDidLoad {
Data *data = [[Data alloc] init];
[data.arr addObject:myObject1]
[data.arr addObject:myObject2]
[data.arr addObject:myObject3]
[data saveDataToDisk];
}
At DisplayData.m, I want to check data.arr by
- (void) viewDidLoad {
Data *data = [[Data alloc] init];
[data loadDataFromDisk];
NSLog(#"length of array is %d",[data.arr count]);
}
On the console, I am getting
length of array is 1
I thought it should be 3 after all.
Please point out what I have just made a mistake in the middle of work if you have any clues about it.

So, I suspect that your "myObjects" are not NSCoding compliant. I just did this:
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:3];
[arr addObject:#"Hello"];
[arr addObject:#" "];
[arr addObject:#"World"];
BOOL ret = [NSKeyedArchiver archiveRootObject:arr toFile:[self getPath]];
NSArray *arr2 = [NSKeyedUnarchiver unarchiveObjectWithFile:[self getPath]];
NSLog(#"count = %d", [arr2 count]);
And the results was "count = 3"

I feel like there's too much code here to do what you're looking for. I think all you need is:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:dataClass] forKey:NSUserDefaultString];
[[NSUserDefaults standardUserDefaults] synchronize];
to save it.
And:
NSData *someData = [[NSUserDefaults standardUserDefaults] objectForKey:NSUserDefaultString];
if (settingsData != nil)
{
dataClass = [NSKeyedUnarchiver unarchiveObjectWithData:settingsData];
}
to retrieve it.

Related

Implementing a Search History feature in iOS

I've got a search page at the moment which will load a list of results for a web-service, but when I return to the search page I would like to 'save' whatever was entered (e.g. 'resto italian') and then display that entry and previous entries into a table view below, like in my following image:
My plan was to use property list serialization - if there isn't already a list, create a property list called history.plist, and populate it with each search term that is made, and display the nearest ten in the table view like above.
What I've tried:
// should create history.plist
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingString:#"history.plist"];
}
/* This is the action for when 'search' is clicked - calls the method above to create
a new plist if it's not already created.
I then try to display the contents of the of the file in the textfield itself
(for testing purposes) but it's not saving/displaying properly at the moment. */
- (IBAction)saveHistory:(id)sender {
NSString *filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
for (int i = 0; i < (sizeof(array)); i++) {
UITextField *theField = self.searchHistory;
theField.text = [NSString stringWithFormat:#"%#", array];
}
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:app];
}
Any links to tutorials attempting to do this, suggestions towards what I should do, or improvements to what I have would be greatly appreciated.
This should fix the problem:
// This is inside viewDidLoad
UIApplication *myApp = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:myApp];
// This is inside my table view - where I'm loading the file data to display in table cells
NSString *myPath = [self dataFilePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:myPath];
if (fileExists) {
NSArray *values = [[NSArray alloc] initWithContentsOfFile:myPath];
for (int i = 0; i < values.count; i++) {
cell.historyDisplay.text = [NSString stringWithFormat:#"%#", [values objectAtIndex:i]];
}
}
// This is the file path for history.plist
- (NSString *)dataFilePath {
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[path objectAtIndex:0] stringByAppendingString:#"history.plist"];
}
// This is my search button - I want to save whatever was typed in the text field, into history.plist, to display in my tableview whenever a user goes to it.
- (IBAction)saveHistory:(id)sender {
NSMutableArray *values = [[NSMutableArray alloc]initWithContentsOfFile:[self dataFilePath]];
if(searchInputTextField.text.length > 0)
[values addObject:searchInputTextField.text];
[values writeToFile:[self dataFilePath] atomically:YES];
[leTableView reloadData];
}
I would use my suggest in comments, but here's some edits to your code that might help in the meantime.
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
for (int i = 0; i <array.count; i++) {
//I don't know what this line means
UITextField *theField = self.searchHistory;
//Change this line to this
theField.text = [NSString stringWithFormat:#"%#", [array objectAtIndex:i]];
}
I would use Core Data, creating a class, i.e. HistoryRecord with attributes termSearched and timestamp of type NSString and NSDate respectively.
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface HistoryRecordManagedObject : NSManagedObject
#property (nonatomic, retain) NSString *termSearched;
#property (nonatomic, retain) NSDate *timestamp;
+ (NSArray *)findEntity:(NSString *)entity withPredicate:(NSPredicate *)predicate
#end
Implementation
#import "HistoryRecordManagedObject.h"
#implementation HistoryRecordManagedObject
#dynamic termSearched;
#dynamic timstamp;
+ (NSArray *)findEntity:(NSString *)entity withPredicate:(NSPredicate *)predicate
{
NSError *error;
NSArray *fetchedObjects;
/* After set all properties, executes fetch request */
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:entity
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entityDesc];
[fetchRequest setPredicate:predicate];
fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
return fetchedObjects;
}
#end
Of course that's not just this! There are some extra stuff that must be done to use Core Data such as create the model. Read a little about it! It's worth!
Good luck!
In the action for searching, just save the search result to NSUserDefaults.
NSMutableArray *searches = [[NSUserDefaults standardUserDefaults] arrayForKey:#"searches"];
[searches insertObject:textField.text atIndex:0];
[[NSUserDefaults standardUserDefaults] setObject:searches forKey:#"searches"];
[[NSUserDefaults standardUserDefaults] synchronize];
Then load the same array for the tables data source and reload the table in viewwillappear and when keyboard is dismissed.
Replace your saveHistory function by below way:
- (IBAction)saveHistory:(id)sender
{
NSMutableArray *values = [[NSMutableArray alloc]initWithContentsOfFile:[self dataFilePath]];
if(searchInputTextField.text.length > 0)
[values addObject:searchInputTextField.text];
[values writeToFile:[self dataFilePath] atomically:YES];
[leTableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return values.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [values objectAtIndex:indexPath.row];
}

How to fetch data from pList in Label

I have a RegistrationController screen to store email-id ,password,DOB,Height,Weight and logininController screen to match email-id and password to log-in purpose.
Now, In some third screen I have to fetch only the Height,Weight from the plist of the logged-in user to display it on the label.now if I Store the values of email-id and password in from LoginViewController in string and call it in the new screen to match if matches then gives Height,Weight ..if it corrects then how to fetch Height,Weight from the plist of the same one.
How can I fetch from the stored plist in a string?
Here is my code:
-(NSArray*)readFromPlist
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
NSString *documentPlistPath = [documentsDirectory stringByAppendingPathComponent:#"XYZ.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:documentPlistPath];
NSArray *valueArray = [dict objectForKey:#"title"];
return valueArray;
}
- (void)authenticateCredentials {
NSMutableArray *plistArray = [NSMutableArray arrayWithArray:[self readFromPlist]];
for (int i = 0; i< [plistArray count]; i++)
{
id object = [plistArray objectAtIndex:i];
if ([object isKindOfClass:[NSDictionary class]]) {
NSDictionary *objDict = (NSDictionary *)object;
if ([[objDict objectForKey:#"pass"] isEqualToString:emailTextFeild.text] && [[objDict objectForKey:#"title"] isEqualToString:passwordTextFeild.text])
{
NSLog(#"Correct credentials");
return;
}
NSLog(#"INCorrect credentials");
} else {
NSLog(#"Error! Not a dictionary");
}
}
}
First get whole value from your plist file after that store this NSArray into NSMutableArray and get the value with its objectAtIndex and valueForKey property..see whole example bellow..
UPDATE :
NSString* plistPath = [[NSBundle mainBundle] pathForResource:#"yourFileName" ofType:#"plist"];
NSArray *contentArray = [NSArray arrayWithContentsOfFile:plistPath];
NSMutableArray *yourArray = [[NSMutableArray alloc] initWithArray:contentArray];
for (int i = 0; i< [yourArray count]; i++)
{
id object = [yourArray objectAtIndex:i];
if ([object isKindOfClass:[NSDictionary class]]) {
NSDictionary *objDict = (NSDictionary *)object;
yourLableWeight.text = [[objDict objectForKey:#"Weight"];// set index with your requirement
yourLableHeight.text = [[objDict objectForKey:#"Height"];
}
hope this help you...
When you enter credentials on login screen to check when it match the credentials with the fetched plist then pass that plist to the next controller. Do something like this
UserViewController *controller = [[UserViewController alloc] initWithNibName:#"UserViewController" bundel:nil];
[controller setUserDictionary:yourPlistDictionary];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
in UserViewController you would have a NSDictionary instance to store the data to show, hope that will help you

Simple NSSArray regarding strings and NSRangeException

I have a simple question. I am designing some simple highscores code yet I am having alot of trouble with it, specifically storing and saving players names. I have not been programming for very long in obj-c, only 2 weeks. I am not quite sure what is going on when I use NSStrings in an array.
Here is the code for saving strings:
-(NSString *) getFilePath2 {
NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[pathArray objectAtIndex:0] stringByAppendingPathComponent:#"savedFile2.plist"];
}
-(void) savePlayerNameData {
NSArray *highScoreNames = [[NSArray alloc]
initWithObjects:
playerName1,
playerName2,
playerName3,
playerName4,
playerName5,
nil];
[highScoreNames writeToFile:[self getFilePath2] atomically:YES];
}
-(void) loadPlayerNameData{
// load data here
NSString *myPath = [self getFilePath2];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:myPath];
if (fileExists) {
NSArray *values = [[NSArray alloc] initWithContentsOfFile:myPath];
playerName1 = [values objectAtIndex:0];
playerName2 = [values objectAtIndex:1];
playerName3 = [values objectAtIndex:2];
playerName4 = [values objectAtIndex:3];
playerName5 = [values objectAtIndex:4];
}
else {
NSLog(#"first Launch. no file yet");
}
}
I end up getting this error :
2012-08-15 22:25:30.780 Pig Fly![5304:f803] *** Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (0) beyond bounds (0)'
*** First throw call stack:
(0x14c5022 0xec5cd6 0x146da48 0x146d9b9 0x14bec30 0xbd21 0x62e2 0x964eb6 0x1499936 0x14993d7 0x13fc790 0x13fbd84 0x13fbc9b 0x13ae7d8 0x13ae88a 0x28626 0x1fdd 0x1f45)
terminate called throwing an exception(lldb)
However, what I find very interesting is that when I write similar code for saving int values, The program runs fine. This is the working int code:
-(NSString *) getFilePath {
NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[pathArray objectAtIndex:0] stringByAppendingPathComponent:#"savedFile.plist"];
}
-(void) saveData {
//save data here
NSArray *highScores = [[NSArray alloc]
initWithObjects:
[NSString stringWithFormat:#"%i",highScore1],
[NSString stringWithFormat:#"%i",highScore2],
[NSString stringWithFormat:#"%i",highScore3],
[NSString stringWithFormat:#"%i",highScore4],
[NSString stringWithFormat:#"%i",highScore5],
nil];
[highScores writeToFile:[self getFilePath] atomically:YES];
}
-(void) loadData{
// load data here
NSString *myPath = [self getFilePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:myPath];
if (fileExists) {
NSArray *values = [[NSArray alloc] initWithContentsOfFile:myPath];
highScore1 = [[values objectAtIndex:0] intValue];
highScore2 = [[values objectAtIndex:1] intValue];
highScore3 = [[values objectAtIndex:2] intValue];
highScore4 = [[values objectAtIndex:3] intValue];
highScore5 = [[values objectAtIndex:4] intValue];
}
else {
NSLog(#"first Launch. no file yet");
}
}
Can anybody tell me what is going on? What are the differences that need to be kept in mind when writing NSArrays for ints and NSStrings?
Make sure that playerName1 is not NULL.

Cannot figure out why my app crashes when I use NSKeyedArchivers / NSKeyedUnarchivers

I am developing my first iphone 'Diary' app, which uses custom 'Entry' objects that hold an NSString title, NSString text and NSDate creationDate. When I try to archive an NSMutableArray of Entry objects, and later retrieve them the next time the view loads, the app crashes. I have gone through a bunch of sample codes and examples that use NSKeyedArchivers, but still couldn't figure out why that happens. I am guessing there is a problem with the initialization of the array that holds the entries but not sure...
Here is the code, maybe you could find something that I have persistently overseen..."
//--------- Entry.m---------------
- (id) initWithCoder:(NSCoder *)aDecoder{
if ((self = [super init])) {
self.title = [[aDecoder decodeObjectForKey:#"title"] retain];
self.text = [[aDecoder decodeObjectForKey:#"text"] retain];
self.created = [[aDecoder decodeObjectForKey:#"created"] retain];
}
return self;
}
- (void) encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.title forKey:#"title"];
[aCoder encodeObject:self.text forKey:#"text"];
[aCoder encodeObject:self.created forKey:#"created"];
}
//-------------- Diary View Controller.m
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}
- (void) writeDataToArchive {
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]
initForWritingWithMutableData:data];
[archiver encodeObject:self.entriesArray forKey:#"entriesArray"];
[archiver finishEncoding];
BOOL result = [data writeToFile:[self dataFilePath] atomically:YES];
[archiver release];
[data release];
}
- (void)addItem:sender {
int count = [entriesArray count] +1;
NSString *newEntryTitle = [NSString stringWithFormat:#"Entry %d", count];
Entry *anEntry = [[Entry alloc] initWithTitle:newEntryTitle text:#"-"
created:[NSDate date]];
[entriesArray addObject:anEntry];
[self.tableView reloadData];
[anEntry release];
[self writeDataToArchive];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSData *data = [[NSMutableData alloc]
initWithContentsOfFile:[self dataFilePath]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]
initForReadingWithData:data];
NSMutableArray *array = [unarchiver decodeObjectForKey:#"entriesArray"];
entriesArray = [array mutableCopy];
[array release];
[unarchiver finishDecoding];
[unarchiver release];
[data release];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath
{
// ... some other stuff
NSUInteger row = indexPath.row;
Entry *entry = [entriesArray objectAtIndex:row];
cell.textLabel.text = entry.title;
return cell;
}
Thanks a lot.
When you read an array back out with NSKeyedUnarchivers you always get an unmutable copy back. You would need to declare *array as NSArray or just get rid of array all together.
entriesArray = [[unarchiver decodeObjectForKey:#"entriesArray"] mutableCopy];
And #JeremyP points out another issue. Since you didn't alloc or retain *array you should not release it.
You should not release array in viewDidLoad because you do not own it.
Please review the Cocoa memory management Rules because there are a couple of other memory management issues in your code. In particular,
self.title = [[aDecoder decodeObjectForKey:#"title"] retain];
self.text = [[aDecoder decodeObjectForKey:#"text"] retain];
self.created = [[aDecoder decodeObjectForKey:#"created"] retain];
in your initWithCoder: method all leak on the assumption the properties are retain or copy.

Memory leak in NSMutableArray, NSArray, NSString in iPhone SDK

In my app, I got Memory leaks in NSMutableArray, NSArray and NSString.
Here is the code.
NSString *subQuery = [NSString stringWithFormat:#"SELECT %# FROM tbl_lang WHERE glossary = '%#'",append1,glossaryName];
NSArray *subArray1 = [[[self returnExecuteQuery:subQuery] mutableCopy] autorelease];
[subArray addObjectsFromArray:subArray1];
NSString *columnQuery = [NSString stringWithFormat:#"select AutoID,%# from tbl_lang where glossary='%#'",lblshortName.text,glossaryName];
NSArray *newArray =[[[self returnExecuteQuery:columnQuery] mutableCopy] autorelease];
[langArray addObjectsFromArray:newArray];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for (int i=0; i<[newArray count]; i++) {
NSString *cellText = [[newArray objectAtIndex:i] valueForKey:[NSString stringWithFormat:#"%#",lblshortName.text]];
if (cellText != (NSString *)[NSNull null] && ![cellText isEqualToString:#""] ) {
NSString *decodedString3 = [NSString stringWithUTF8String:[cellText cStringUsingEncoding:[NSString defaultCStringEncoding]]];
[tempArray addObject:[NSString stringWithFormat:#"%# : %#",lblshortName.text, decodedString3]];
}
else {
[tempArray addObject:#"<empty>"];
}
NSString *detail = #"_________________";
for (int j=0; j<[lableNameArray count]; j++) {
NSString *checkNull=[[subArray1 objectAtIndex:i] valueForKey:[NSString stringWithFormat:#"%#",[lableNameArray objectAtIndex:j]]];
if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
{
NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
detail = [NSString stringWithFormat:#"%#\n%# : %# ",detail,[lableNameArray objectAtIndex:j],decodedString4];
}
}
[detailTextArray addObject:detail];
}
When I run in Instruments I got leaks in
-subArray1 in second line.
-detail (NSString) in second for loop.
And subArray and langArray are my global arrays.
If I remove mutableCopy from NSArray *newArray =[[[self returnExecuteQuery:columnQuery] mutableCopy] autorelease]; and NSArray *subArray1 = [[[self returnExecuteQuery:subQuery] mutableCopy] autorelease]; then subArray and langArray doesnot retain values.
How to avoid memory leak in this code?
Olease try this one, in above code you are creating two many objects that belong to autorelease pool here is one version where I tried to handle release of those string variables.
Second this is that the leak of detail is because you are de-referencing it many times in your code. And for subArray1 please see the comment
NSMutableString *subQuery =[ [NSMutableString alloc] initWithFormat:#"SELECT %# FROM tbl_lang WHERE glossary = '%#'",append1,glossaryName];
// please make returnExecuteQuery's returned array autorelease if it is not.
NSArray *subArray1 = [[self returnExecuteQuery:subQuery] mutableCopy] ;
[subArray addObjectsFromArray:subArray1];
[subQuery release];
NSMutableString *columnQuery ==[ [NSMutableString alloc] initWithFormat:#"select AutoID,%# from tbl_lang where glossary='%#'",lblshortName.text,glossaryName];
NSArray *newArray =[[self returnExecuteQuery:columnQuery] mutableCopy] ;
[langArray addObjectsFromArray:newArray];
[columnQuery relese];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for (int i=0; i<[newArray count]; i++) {
NSMutableString *tempKey = [[NSMutableString alloc]initWithFormat:#"%#",lblshortName.text]];
NSString *cellText = [[newArray objectAtIndex:i] valueForKey:tempKey];
[tempKey release];
if (cellText != (NSString *)[NSNull null] && ![cellText isEqualToString:#""] ) {
NSString *decodedString3 = [NSString stringWithUTF8String:[cellText cStringUsingEncoding:[NSString defaultCStringEncoding]]];
NSMutableString *tempString = [[NSMutableString alloc] initWithFormat:#"%# : %#",lblshortName.text, decodedString3]];
[tempArray addObject:tempString];
[tempString release];
}
else {
[tempArray addObject:#"<empty>"];
}
NSMutableString *detail = nil;
for (int j=0; j<[lableNameArray count]; j++)
{
detail = [[ NSMutableString alloc]initWithString:#"_________________"];
NSMutableString *key = [[NSMutableString alloc]initWithFormat:#"%#",[lableNameArray objectAtIndex:j]];
NSString *checkNull=[[subArray1 objectAtIndex:i] valueForKey:key];
[key release];
if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
{
NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
[detail setString:[NSString stringWithFormat:#"%#\n%# : %# ",detail,[lableNameArray objectAtIndex:j],decodedString4]];
}
[detailTextArray addObject:detail];
[detail release];
}
}
[subArray1 release];
[newArray release];
UPDATE : Please do read comments in the code and reply back so that things could be improved.
NSMutableString *subQuery =[ [NSMutableString alloc] initWithFormat:#"SELECT %# FROM tbl_lang WHERE glossary = '%#'",append1,glossaryName];
//*****NOTE THIS POINT ----> please make returnExecuteQuery's returned array autorelease if it is not.
NSArray *subArray1 = [[self returnExecuteQuery:subQuery] mutableCopy] ;
[subArray addObjectsFromArray:subArray1];
[subQuery release];
NSMutableString *columnQuery ==[ [NSMutableString alloc] initWithFormat:#"select AutoID,%# from tbl_lang where glossary='%#'",lblshortName.text,glossaryName];
//*****NOTE THIS POINT ----> please make returnExecuteQuery's returned array autorelease if it is not.
NSArray *newArray =[[self returnExecuteQuery:columnQuery] mutableCopy] ;
[langArray addObjectsFromArray:newArray];
[columnQuery relese];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for (int i=0; i<[newArray count]; i++) {
NSMutableString *tempKey = [[NSMutableString alloc]initWithFormat:#"%#",lblshortName.text]];
NSString *cellText = [[newArray objectAtIndex:i] valueForKey:tempKey];
[tempKey release];
if (cellText != (NSString *)[NSNull null] && ![cellText isEqualToString:#""] ) {
NSString *decodedString3 = [NSString stringWithUTF8String:[cellText cStringUsingEncoding:[NSString defaultCStringEncoding]]];
NSMutableString *tempString = [[NSMutableString alloc] initWithFormat:#"%# : %#",lblshortName.text, decodedString3]];
[tempArray addObject:tempString];
[tempString release];
}
else {
[tempArray addObject:#"<empty>"];
}
NSMutableString *detail = [[ NSMutableString alloc]initWithString:#"_________________"];
for (int j=0; j<[lableNameArray count]; j++)
{
NSMutableString *key = [[NSMutableString alloc]initWithFormat:#"%#",[lableNameArray objectAtIndex:j]];
NSString *checkNull=[[subArray1 objectAtIndex:i] valueForKey:key]; //also here if you note you are using subArray1 not subArray?
[key release];
if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
{
NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
[detail setString:[NSString stringWithFormat:#"%#\n%# : %# ",detail,[lableNameArray objectAtIndex:j],decodedString4]];
break;//I am not sure why you are checking this condition but assume that you want to get NOT NULL VALUE and add it to array?
}
}
[detailTextArray addObject:detail];
[detail release];
}
[subArray1 release];
[newArray release];
UPDATE 2:
if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
{
NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
[detail appendFormat:#"%#\n%# : %# ",detail,[lableNameArray objectAtIndex:j],decodedString4]];
}
Thanks,
Not sure what is causing the memory leak, but this may help. This is a more direct way of copying the arrays, and may result in avoiding the leak:
NSArray *langArray =[[NSArray alloc] initWithArray: [self returnExecuteQuery:columnQuery] copyItems: YES];
This basically makes a one-level deep copy of the array returned by returnExecuteQuery. You can read about it in more detail in Collections Programming Topics.
I'm not sure how mutableCopy works and that may have something to do with the leak. If it copies the objects in the old array & then adds them to the new array, they may enter the array with a retain count of 2 (1 from the copy, and 1 from being added to an array.) It doesn't make much sense that it should work this way. But, if it does, that could account for the leak.
You could start by releasing your tempArray once done with it (after the loops).
Often, the higher levels leaks are hidden in the flood of lower level ones (ie a container leaking causes all its content to be leaked as well), which might be the case for your string.
Using mutableCopy] autorelease]; is fine by the way.