NSMutable Array always adding the same pointer - iphone

The following code should add different objects to an NSMutableArray however it adds the same object each time:-
for(int i =0; i < [results count];i++)
{
Reservation *r = [[Reservation alloc] init];
NSDictionary *dict = [results objectAtIndex: i];
r.resId = [dict objectForKey:#"reservationrequest_id"];
r.driver = [dict objectForKey:#"driver_name"];
r.vehicle = [dict objectForKey:#"billing_registration"];
r.startDate = [dict objectForKey:#"hire_from_date"];
r.endDate = [dict objectForKey:#"hire_to_date"];
r.status = [dict objectForKey:#"status_type"];
[self.bookingsObjectArray addObject:r];
[r release];
r = nil;
}
I have exactly the same code that works fine in another part of my app it just uses a Groups class instead of Reservation.
When debugging the code I found that when it does [r release]; 'r' is greyed out but still keeps the same pointer. When it goes back to Reservation *r = [[Reservation alloc] init];
'r' has the same pointer as last time.
Any ideas what might be causing the problem? Thanks in advance.
Chris

Related

keysSortedByValueUsingSelector crashes but sortedArrayUsingSelector runs fine

I found a workaround myself, but still trying to understand the problem.
I created a Autocomplete text field with the use of uitableview which is hidden until textfield is edited. The UI part works fine. It's the searching for the results part that's the problem. I declared a local NSMutableDictionary to store my results because I wanted the results to be sorted by the key's values.
if I call keysSortedByValueUsingSelector on the dictionary directly, it crashes. However if I get the keys by [dict allKeys] first, then call sortedArrayUsingSelector, it works fine:
// This commented out line will crash
// NSArray *sortedKeysArray = [dict keysSortedByValueUsingSelector:#selector(compare:)];
// The next two lines runs fine.
NSArray *keyArray = [dict allKeys];
NSArray *sortedKeysArray = [keyArray sortedArrayUsingSelector:#selector(compare:)];
Here is the complete source code for the search method:
- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring
{
// Put anything that starts with this substring into the autocompleteUrls array
// The items in this array is what will show up in the table view
[autocomplete_symbol_array removeAllObjects];
rRSIAppDelegate *appDelegate = (rRSIAppDelegate *)([[UIApplication sharedApplication] delegate]);
NSString *input_str = [substring uppercaseString];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
int i = 0;
for(SymbolInfo *symbol_info in appDelegate.m_symbol_info_array)
{
i++;
NSString *info_str = [[[symbol_info.m_symbol uppercaseString] stringByAppendingString:#"|"] stringByAppendingString:[symbol_info.m_company_name uppercaseString]];
NSUInteger pos = [info_str rangeOfString:input_str].location;
if (pos != NSNotFound)
{
int tmp = pos * 10000 + i;
NSNumber *map_key = [[NSNumber alloc] initWithInt:tmp];
[dict setObject:symbol_info forKey:map_key];
}
}
// This commented out line will crash
// NSArray *sortedKeysArray = [dict keysSortedByValueUsingSelector:#selector(compare:)];
// The next two lines runs fine.
NSArray *keyArray = [dict allKeys];
NSArray *sortedKeysArray = [keyArray sortedArrayUsingSelector:#selector(compare:)];
for (NSNumber *key in sortedKeysArray)
{
SymbolInfo *symbol_info = [dict objectForKey:key];
[autocomplete_symbol_array addObject:symbol_info];
}
// NSLog(#"everything added: %d", [autocomplete_symbol_array count]);
[autocompleteTableView reloadData];
}
The NSMutableDictionary's method is:
- (void)setObject:(id)anObject forKey:(id < NSCopying >)aKey;
This means that the key should implement the NSCopying protocol.

add data to NSMUtableArrray with keys by for loop

I'm new in iPhone, I want to add elements to NSMutableArray with each element's name
I created a MutableArray for keys , then other array for elements that I get them from object called Pages.
I wrote the following code
NSMutableArray *myArray;
NSMutableArray *arrayKey = [[NSMutableArray alloc] initWithObjects:#"b_pag_id", #"b_pag_bo_id", #"b_pag_num", #"b_pag_note", #"b_page_mark", #"b_page_stop", #"b_pag_user_id", nil];
for (int x=0; x<[pages count]; x++) {
Pages *myPages = (Pages *)[self.pages objectAtIndex:x];
NSString *b_pag_id2 = [NSString stringWithFormat:#"%d",myPages.b_pag_id];
NSString *b_pag_bo_id2 = [NSString stringWithFormat:#"%d",myPages.b_pag_bo_id];
NSString *b_pag_num2 = [NSString stringWithFormat:#"%d",myPages.b_pag_num];
NSString *b_pag_note2 = myPages.b_pag_note;
NSString *b_page_mark2 = [NSString stringWithFormat:#"%d",myPages.b_page_mark];
NSString *b_page_stop2 = [NSString stringWithFormat:#"%d",myPages.b_page_stop];
NSString *b_pag_user_id2 = [NSString stringWithFormat:#"%d",myPages.b_pag_user_id];
NSMutableArray *arrayValue = [[NSMutableArray alloc] initWithObjects:b_pag_id2, b_pag_bo_id2, b_pag_num2, b_pag_note2, b_page_mark2, b_page_stop2, b_pag_user_id2, nil];
NSDictionary *theReqDictionary = [NSDictionary dictionaryWithObjects:arrayValue forKeys:arrayKey];
myArray = [NSMutableArray arrayWithObjects:theReqDictionary,nil];
}
NSLog(#"array size: %d", [myArray count]);
I want to add every element to its key for example
element (b_pag_id2) its key (b_pag_id) ..etc
is this right ?? or how to do this ??
consider that NSLog(#"array size: %d", [myArray count]); gives me 1 and the size of my elements is 14
Before the loop you need to initialize the aray
NSMutableArray *myArray = [NSMutableArray array];
Inside the loop replace following:
myArray = [NSMutableArray arrayWithObjects:theReqDictionary,nil];
with
[myArray addObject:theReqDictionary];
The problem is that you are creating a new array with 1 dictionary in every loop iteration. Instead you need to initialize the array and add values one by one.
Each time through your loop you are creating a new array for myArray that has only one element. You should initialize an empty NSMutableArray before the loop and then simply add your new object to it instead of using arrayWithObjects: to create myArray..
Here i'm giving a short example, and i hope this will help you.
see this code :-
NSMutableArray *arrayValue = [[NSMutableArray alloc]initWithObjects:#"Value1",#"Value2",#"Value3", nil];
NSMutableArray *arrayKey = [[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3", nil];
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];
for(int i=0;i<3;i++)
{
[dic setObject:[arrayValue objectAtIndex:i] forKey:[arrayKey objectAtIndex:i]];
}
//and you can see this by printing it using nslog-
NSLog(#"%#",[dic valueForKey:#"1"]);
Thank you!!!

Trying to find leak of type NSMutableArray. Instruments shows leak in method.

I eliminated all the leaks from my current app. However Instruments constantly tells me that I have a leak in the method shown below.
The leak is of type NSMutableArray and has a size of either 16 or 32 bytes. Yes, I know that's not much but it adds up. Also see it as an academic question that I need to solve to make my code leakless.
+ (id) meterFromDict:(NSDictionary*)dict {
Meter* resMeter = [[Meter alloc] initWithType:[[dict objectForKey:#"MeterBase"] intValue]];
//NSLog(#"dict: %#",dict);
resMeter.volume = nil;
resMeter.sounds = nil;
resMeter.repeats = nil;
resMeter.volume = [[[NSMutableArray alloc] initWithArray:[dict objectForKey:#"volumeArray"]] autorelease];
resMeter.sounds = [[[NSMutableArray alloc] initWithArray:[dict objectForKey:#"soundsArray"]] autorelease];
resMeter.repeats = [[[NSMutableArray alloc] initWithArray:[dict objectForKey:#"repeatsArray"]] autorelease];
//NSLog(#"MeterFromDict called and resmeter.repeats count is : %i",[resMeter.repeats count]);
resMeter.bpm = [[dict objectForKey:#"BPM"] floatValue];
return [resMeter autorelease];
}
Without looking at your Instruments output directly I can't tell exactly, but you're writing some redundant code: Try this:
+ (id) meterFromDict:(NSDictionary*)dict {
Meter* resMeter = [[Meter alloc] initWithType:[[dict objectForKey:#"MeterBase"] intValue]];
//NSLog(#"dict: %#",dict);
resMeter.volume = [dict objectForKey:#"volumeArray"];
resMeter.sounds = [dict objectForKey:#"soundsArray"];
resMeter.repeats = [dict objectForKey:#"repeatsArray"];
//NSLog(#"MeterFromDict called and resmeter.repeats count is : %i",[resMeter.repeats count]);
resMeter.bpm = [[dict objectForKey:#"BPM"] floatValue];
return [resMeter autorelease];
}
There's no point in nilling your properties before assigning new values to them.
Also, No point creating new arrays for arrays that you already have. And if you have properly declared your volume, sounds and repeats properties with copy instead of retain.
Try that and see if it works better.

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.

Can not load an archived NSMutableArray into a new NSMutableArray

The App will save the NSMutableArray into a archive with no problems but as soon as I try and load the NSMutableArray back into a new NSMutableArray # viewDidLoad the app will crash. I put a break point at the end of the code where "tempArray = [unarchiver decodeObjectForKey:kDataKey46];" and tempArray is being loaded with the archived array but when I go through the "for" loop # "[poolListData addObject:testTemp];" "poolListData" does not hold the data from "tempArray". Also if I did not use a break point and just let the app try to load, the app will crash...What do you guys think?
Thank you for your time!
Jeff
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
field1.text = [unarchiver decodeObjectForKey:kDataKey1];
// snip another bunch of fields
field37.text = [unarchiver decodeObjectForKey:kDataKey37];
soundOn = [unarchiver decodeBoolForKey:kDataKey38];
soundVolumeSlider.value = [unarchiver decodeDoubleForKey:kDataKey39];
soundVolumeValue = [unarchiver decodeDoubleForKey:kDataKey39];
tempArray = [unarchiver decodeObjectForKey:kDataKey46];
[unarchiver finishDecoding];
for(int i = 0; i < [tempArray count]; i++)
{
NSData *testTemp = 0;
//NSString *temp = [tempArray objectAtIndex:i];
testTemp = [tempArray objectAtIndex:i];
[poolListData addObject:testTemp];
//[poolListData addObjectsFromArray:tempArray];
}
/*
firstNameTextField.text = field1.text;
lastNameTextField.text = field2.text;
adressTextField.text = field3.text;
emailTextField.text = field4.text;
*/
[tempArray release];
[unarchiver release];
[data release];
}
I believe this is at least partially a memory management error. The decodeObjectForKey call returns an autoreleased object, so that it’s a bug to release the tempArray at the end of the function. This would be the reason your app crashes. As for poolListData not holding the unarchived array’s contents, maybe you simply forgot to initialize it and you are trying to add items into a nil array?
If you call unarchive, and are not seeing any values, then the array held something that could not be archived. I believe UIImage would be an example of something you might have in the array to try and save. The key to your problem is, what types do you have in that tempArray when you archive it.