iOS 5 sdk issue with mutable arrays - iphone

Hello I created a app on iOS 4.3.3 and than downloaded Xcode 4.2.1 and iOS sdk 5. It's a navigation-based application and it has a mutable array for the tableview but it won't create any strings for the array, so i added an object to array in the viewdidload but it is not working! So i added NSlog to the objects in my array and it says null! What should i do?
Here's the viewdidload:
- (void)viewDidLoad
{
[super viewDidLoad];
self.soldc = [NSMutableArray arrayWithCapacity:0];
self.color = [NSMutableArray arrayWithCapacity:0];
appdelegate = (yard_sale_managerAppDelegate *)[[UIApplication sharedApplication] delegate];
appdelegate.object = self;
NSMutableArray *loadi = [[NSMutableArray alloc]initWithCapacity:0];
self.items = loadi;
self.sold = [NSMutableArray arrayWithCapacity:0];
self.prices = [NSMutableArray arrayWithCapacity:0];
alert = [[UIAlertView alloc] initWithTitle:#"Add product" message:#"Enter your product name and price." delegate:self cancelButtonTitle:#"Add" otherButtonTitles:#"Cancel", nil];
[alert addTextFieldWithValue:#"" label:#"name"];
[alert addTextFieldWithValue:#"" label:#"price"];
add = [alert textFieldAtIndex:0];
add.keyboardType = UIKeyboardTypeAlphabet;
add.keyboardAppearance = UIKeyboardAppearanceAlert;
add.autocapitalizationType = UITextAutocapitalizationTypeWords;
add.autocorrectionType = UITextAutocorrectionTypeNo;
add2 = [alert textFieldAtIndex:1];
add2.keyboardType = UIKeyboardTypeNumberPad;
add2.keyboardAppearance = UIKeyboardAppearanceAlert;
add2.autocapitalizationType = UITextAutocapitalizationTypeWords;
add2.autocorrectionType = UITextAutocorrectionTypeNo;
NSLog(#"%i", [color count]);
alert.tag=1;
self.resa = [[UIAlertView alloc] initWithTitle:#"Sale results" message:#"temple" delegate:self cancelButtonTitle:#"Close" otherButtonTitles: nil];
self.items = [NSMutableArray arrayWithContentsOfFile:[self itemsp]];
self.prices = [NSMutableArray arrayWithContentsOfFile:[self pricesp]];
self.sold = [NSMutableArray arrayWithContentsOfFile:[self soldp]];
self.soldc = [NSMutableArray arrayWithContentsOfFile:[self soldcp]];
self.color = [NSMutableArray arrayWithContentsOfFile:[self colorsp]];
if ([self.soldc count]==0) {
}
//self.soldc = [NSMutableArray arrayWithContentsOfFile:[self soldcp]];
self.color = [NSMutableArray arrayWithContentsOfFile:[self colorsp]];
[loadi release];
self.resa.tag = 2;
[self.items addObject:#"chair"];
[self.prices addObject:#"30"];
[self.color addObject:#"0"];
NSLog(#"%#",self.items);
}
If you need more information tell me!
This is the log:
2012-01-08 21:31:13.409 yard sale manager[1152:f803] 0
2012-01-08 21:31:13.411 yard sale manager[1152:f803] (null)
edit: read this its important!!!!!
a lot of people didn't notice that piece of code:
[self.items addObject:#"chair"];
[self.prices addObject:#"30"];
[self.color addObject:#"0"];
NSLog(#"%#",self.items);

This line
self.color = [NSMutableArray arrayWithCapacity:0];
instantiates and assigns an empty array, you then do not add anything to it therefore the 0 count.
Then this line
self.items = [NSMutableArray arrayWithContentsOfFile:[self itemsp]];
is probably the cause. Does [self itemsp] return a valid file path that points to a file that can be parsed into an NSArray.
There are also a lot of other issues with this code.
Update
This line
self.items = [NSMutableArray arrayWithContentsOfFile:[self itemsp]];
must be returning nil.
Confirm by adding this line straight after it
NSLog(#"%#", self.items);
How can I make this assumption
The reason I am making this assumption is because you are getting (null). When you call addObject: on nil you will get nil returned and it is a no-op. As you can see from this snippet
NSMutableArray *myArray = nil;
[myArray addObject:#"Test"];
NSLog(#"%#", myArray);
// => 2012-01-08 20:54:04.708 Untitled[4199:707] (null)
Just because myArray holds a pointer to an NSMutableArray it does not mean that you actually have one.
Therefore the last time you assign to self.items is in:
self.items = [NSMutableArray arrayWithContentsOfFile:[self itemsp]];
which means [NSMutableArray arrayWithContentsOfFile:[self itemsp]] is returning nil

Given that NSLog(#"%#",self.items); prints (null) it follows that the self.items NSMutableArray is never created. The only way that could happen is if
self.items = [NSMutableArray arrayWithContentsOfFile:[self itemsp]];
returns nil, that is does not read anything, probably because there is nothing at the path.
NSLog self.items right after the statement:
self.items = [NSMutableArray arrayWithContentsOfFile:[self itemsp]];
If you are trying to write to the app bundle that won't work, you need to write a directory such as the sandboxed Documents directory.

Related

i had 2 arrays with objects and the same nameobject should be cancelled only one time

I have input as two arrays shown below
NSArray *array1=[[NSArray alloc]initWithObjects:#"1",#"2",#"3", nil];
NSArray *array2=[[NSArray alloc]initWithObjects:#"1",#"2",#"1", nil];
the output should resemble like this.
the same element should be cancelled only one time.
NSArray *array3=[[NSArray alloc]initWithObjects:#"1",#"2", nil];
THANKS IN ADVANCE.....
NSArray *array1 = #[#"1",#"2",#"3"];
NSArray *array2 = #[#"1",#"2",#"1"];
NSMutableSet *allElemets = [NSSet setWithArray:array1];
[allElemets addObjectsFromArray:array2];
This will return you all elements without duplicates.
In this case it will be
#"1",#"2",#"3"
Edit:
This will return the intersection of the arrays
NSMutableSet *set1 = [NSMutableSet setWithArray:array1];
NSSet *set2 = [NSSet setWithArray:array2];
[set1 intersectSet:set2];
Use NSCountedSet for the above situation
NSMutableArray *array1=[[NSMutableArray alloc]initWithObjects:#"r",#"a",#"r",#"r",#"r", nil];
NSArray *array2=[[NSArray alloc]initWithObjects:#"b",#"c",#"r", nil];
NSMutableSet *setOne = [NSMutableSet setWithArray: array1];
NSSet *setTwo = [NSSet setWithArray: array2];
[setOne unionSet:setTwo];
NSArray *arrayOneResult = [setOne allObjects];
NSLog(#"%#",arrayOneResult);
NSMutableArray *resultArray = [[NSMutableArray alloc]init];
NSCountedSet *set = [[NSCountedSet alloc] initWithArray:arrayOneResult];
for (id item in set)
{
NSCountedSet *set1 = [[NSCountedSet alloc] initWithArray:array1];
NSCountedSet *set2 = [[NSCountedSet alloc]initWithArray:array2];
int diff = abs([set1 countForObject:item] - [set2 countForObject:item]);
for (int i = 0 ;i < diff ;i++ ) {
[resultArray addObject:item];
}
}
NSLog(#"the array : %#",resultArray );
f you are fine with sets instead of arrays, you can use NSMutableSet instead of NSArray. NSMutableSet has nice methods like intersectSet: and minusSet:
if([[array1 objectAtIndex:i] isEqualToString:[array2 objectAtIndex:i]])
{
[array2 removeObjectAtIndex: i];
NSLog(#"same element removed.");
}
array3 = [firstArray arrayByAddingObjectsFromArray:secondArray];
or
NSMutableSet *set = [NSMutableSet setWithArray:array1];
[set addObjectsFromArray:array2];
array3 = [set allObjects];
Two arrays are compared and duplicate values are removed, you get your values.
Here tHe Code goes
EDIt: This WOuld remove the Duplicate Value add Unique value.
NSArray *array1=[[NSArray alloc]initWithObjects:#"1",#"2",#"3", nil];
NSArray *array2=[[NSArray alloc]initWithObjects:#"1",#"2",#"1", nil];
//Here Create nEw Array with Arra1
NSMutableArray * newArray =[[NSMutableArray alloc] initWithArray:array1];
for(int index=0; index<[array2 count];index++)
{
id object =[array2 objectAtIndex:index];
if(![newArray containsObject:object])//this methods Returns YES/NO
{
[newArray addObject: object];
}
}

Objective c memory leak

Here are two methods that return a dictionary of my custom four-propery objects. They make arrays of strings, floats and BOOLs to put in the Chemical objects, then build a dictionary from the arrays. I'm new enough to the whole memory management game that I'm not always sure when I own something and when to release it. I'm making all kinds of strings on the fly.
Here's the thing: The static analyzer sees no problem with the first method, - (id)generateChlorineDictionary but says there's a leak in the second one, - (id)generateCYADictionary. It says it starts at the NSMutableArray *cyaGranulesArray... and then goes to NSDictionary *cyaDictionary... and finally to the return cyaDictionary statement.
Here are the two methods; sorry they're so long!
EDIT: Changed name from generateChlorineDictionary to newChlorineDictionary
Removed a release that happened after the return
- (id)newChlorineDictionary {
// Sets up the array for the Bleach key
NSMutableArray *bleachArray = [[NSMutableArray alloc] init];
NSArray *bleachConcentrationArray = [[NSArray alloc] initWithObjects:#"6%", #"10%", #"12%", nil];
float bleachConstantArray[] = {0.0021400, 0.0012840, 0.0010700};
for (int i=0; i<3; i++) {
Chemical *bleachChemical = [[Chemical alloc] initWithChemical:#"Bleach"
andConcentration:[bleachConcentrationArray objectAtIndex:i]
andConstant:bleachConstantArray[i]
andIsLiquid:YES];
[bleachArray addObject:bleachChemical];
NSLog(#"bleachChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", bleachChemical.chemName, bleachChemical.chemConcentration, bleachChemical.chemConstant, bleachChemical.chemIsLiquid);
[bleachChemical release];
}
bleachConcentrationArray = nil;
// Sets up the array for the Trichlor key
NSMutableArray *trichlorArray = [[NSMutableArray alloc] init];
Chemical *trichlorChemical = [[Chemical alloc] initWithChemical:#"Trichlor"
andConcentration:#"90%"
andConstant:0.0001480
andIsLiquid:NO];
[trichlorArray addObject:trichlorChemical];
NSLog(#"trichlorChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", trichlorChemical.chemName, trichlorChemical.chemConcentration, trichlorChemical.chemConstant, trichlorChemical.chemIsLiquid);
[trichlorChemical release];
// Sets up the array for the Dichlor key
NSMutableArray *dichlorArray = [[NSMutableArray alloc] init];
NSArray *dichlorConcentrationArray = [[NSArray alloc] initWithObjects:#"56%", #"62%", nil];
float dichlorConstantArray[] = {0.0002400, 0.0002168};
for (int i=0; i<2; i++) {
Chemical *dichlorChemical = [[Chemical alloc] initWithChemical:#"Dichlor"
andConcentration:[dichlorConcentrationArray objectAtIndex:i]
andConstant:dichlorConstantArray[i]
andIsLiquid:NO];
[dichlorArray addObject:dichlorChemical];
NSLog(#"dichlorChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", dichlorChemical.chemName, dichlorChemical.chemConcentration, dichlorChemical.chemConstant, dichlorChemical.chemIsLiquid);
[dichlorChemical release];
}
dichlorConcentrationArray = nil;
// Sets up the array for the Cal Hypo key
NSMutableArray *calHypoArray = [[NSMutableArray alloc] init];
NSArray *calHypoConcentrationArray = [[NSArray alloc] initWithObjects:#"48%", #"53%", #"65", #"73", nil];
float calHypoConstantArray[] = {0.0002817, 0.0002551, 0.0002080, 0.0001852};
for (int i=0; i<2; i++) {
Chemical *calHypoChemical = [[Chemical alloc] initWithChemical:#"Cal Hypo"
andConcentration:[calHypoConcentrationArray objectAtIndex:i]
andConstant:calHypoConstantArray[i]
andIsLiquid:NO];
[calHypoArray addObject:calHypoChemical];
NSLog(#"calHypoChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", calHypoChemical.chemName, calHypoChemical.chemConcentration, calHypoChemical.chemConstant, calHypoChemical.chemIsLiquid);
[calHypoChemical release];
}
calHypoConcentrationArray = nil;
// Sets up the array for the Li Hypo key
NSMutableArray *liHypoArray = [[NSMutableArray alloc] init];
Chemical *liHypoChemical = [[Chemical alloc] initWithChemical:#"Li Hypo"
andConcentration:#"90%"
andConstant:0.0003800
andIsLiquid:NO];
[liHypoArray addObject:liHypoChemical];
NSLog(#"liHypoChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", liHypoChemical.chemName, liHypoChemical.chemConcentration, liHypoChemical.chemConstant, liHypoChemical.chemIsLiquid);
[liHypoChemical release];
// The array of keys for the chlorine chemicals
NSArray *chlorineKeys = [[NSArray alloc] initWithObjects:#"Bleach", #"Trichlor", #"Dichlor", #"Cal Hypo", #"Li Hypo", nil];
// The array of values for the chlorine chemicals
NSArray *chlorineValues = [[NSArray alloc] initWithObjects:bleachArray, trichlorArray, dichlorArray, calHypoArray, liHypoArray, nil];
[bleachArray release];
[trichlorArray release];
[dichlorArray release];
[calHypoArray release];
[liHypoArray release];
// The dictionary to hold the arrays of chlorine chemical objects
NSDictionary *chlorineDictionary = [[NSDictionary alloc] initWithObjects:chlorineValues forKeys:chlorineKeys];
[chlorineValues release];
[chlorineKeys release];
return chlorineDictionary;
}
EDIT: Changed name from generateCYADictionary to newCYADictionary
Removed a release that happened after the return
- (id)newCYADictionary {
// Sets up the array for the CYA Granules key
NSMutableArray *cyaGranulesArray = [[NSMutableArray alloc] init];
Chemical *cyaGranulesChemical = [[Chemical alloc] initWithChemical:#"CYA Granules"
andConcentration:#""
andConstant:0.0001330
andIsLiquid:NO];
[cyaGranulesArray addObject:cyaGranulesChemical];
NSLog(#"cyaGranulesChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", cyaGranulesChemical.chemName, cyaGranulesChemical.chemConcentration, cyaGranulesChemical.chemConstant, cyaGranulesChemical.chemIsLiquid);
[cyaGranulesChemical release];
// Sets up the array for the Liquid Stabilizer key
NSMutableArray *liquidStabilizerArray = [[NSMutableArray alloc] init];
Chemical *liquidStabilizerChemical = [[Chemical alloc] initWithChemical:#"Liquid Stabilizer"
andConcentration:#""
andConstant:0.0003460
andIsLiquid:YES];
[liquidStabilizerArray addObject:liquidStabilizerChemical];
NSLog(#"liquidStabilizerChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", liquidStabilizerChemical.chemName, liquidStabilizerChemical.chemConcentration, liquidStabilizerChemical.chemConstant, liquidStabilizerChemical.chemIsLiquid);
[liquidStabilizerChemical release];
// The array of keys for the CYA chemicals
NSArray *cyaKeys = [[NSArray alloc] initWithObjects:#"CYA Granules", #"Liquid Stabilizer", nil];
// The array of values for the CYA chemicals
NSArray *cyaValues = [[NSArray alloc] initWithObjects:cyaGranulesArray, liquidStabilizerArray, nil];
[cyaGranulesArray release];
[liquidStabilizerArray release];
// The dictionary to hold the arrays of CYA chemical objects
NSDictionary *cyaDictionary = [[NSDictionary alloc] initWithObjects:cyaValues forKeys:cyaKeys];
[cyaKeys release];
[cyaValues release];
return cyaDictionary;
}
Replace the
return cyaDictionary;
[cyaDictionary release];
With
return [cyaDictionary autorelease];
Or, you might replace the
NSDictionary *chlorineDictionary = [[NSDictionary alloc] initWithObjects:chlorineValues forKeys:chlorineKeys];
With
NSDictionary *chlorineDictionary = [NSDictionary dictionaryWithObjects:chlorineValues forKeys:chlorineKeys];
Instead of adding the autorelease.
In your original implementation the [cyaDictionary release]; is never executed (because it is after return).
You can use this dictionary outside this method and you shouldn't release it there.
You might want also return a retained object (without the autorelease) and release it outside the method. In this case you should start the method name with "new" or "alloc"...
EDIT (Important):
You should use only one of my suggestions.
Use the autorelease in the return line
Use the dictionaryWith...
Add the "new" or "alloc" prefix in the method name and release the returned object outside this method.
If you replace the alloc init with dictionaryWith... then you get an autoreleased object. And then, if you release it in the outer method then you have a serious problem (the object will try to release itself after the current runloop of the thread and it may crash the app because the object will already be released by you).
EDIT (due to one of the comments)
If you want to create a property that will return a dictionary:
// MyClass.h file
#interface MyClass : NSObject {
..
NSDictionary *_dict1;
..
}
#property (nonatomic, retain) NSDictionary *dict1;
..
#end
// MyClass.m file
#implementation MyClass
#synthesize dict1 = _dict1;
..
- (NSDictionary *)dict1 {
if (_dict1 == nil) {
NSDictionary *dict1Temp = [NSDictionary new];
// Your implementation goes here...
self.dict1 = dict1Temp;
[dict1Temp release];
}
}
..
- (void)dealloc {
[_dict1 release];
[suoer dealloc];
}
#end

NSArray runtime array

I have got I have got two methods both in different classes. One is class method and other is instance method. i am calling class method from instance method. When instance method finishes it gives runtime error "EXC_BAD_ACCESS".
#import "xmlObject.h"
#import "textmeAppDelegate.h"
#implementation Class1
- (void)method1 {
textmeAppDelegate *del = (textmeAppDelegate *)[[UIApplication sharedApplication] delegate];
NSArray *bgColor = [[NSArray alloc] initWithArray:[xmlObject fetchImmediateChildrenValues:[del.navigationbarStyle objectForKey:#"backgroundcolor"]]];
UIColor *color = [UIColor colorWithRed:[[bgColor objectAtIndex:3] floatValue] green:[[bgColor objectAtIndex:2] floatValue] blue:[[bgColor objectAtIndex:1] floatValue] alpha:[[bgColor objectAtIndex:0] floatValue]];
CGContextSetFillColor(context, CGColorGetComponents([color CGColor]));
CGContextFillRect(context, rect);
[bgColor release];
}
#end
#implementation xmlObject
+ (NSArray *) fetchImmediateChildrenValues:(NSMutableDictionary *) node {
NSMutableDictionary *tmp = [[node objectForKey:#"children"] retain];
NSArray *keys = [[NSArray alloc] initWithArray:[tmp allKeys]];
keys = [keys sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
NSMutableArray *pushArr = [[[NSMutableArray alloc] init] autorelease];
NSString *val = [[NSString alloc] init];
for(NSString *str in keys) {
val = (NSString *)[[tmp objectForKey:str] objectForKey:#"innertext"];
[pushArr addObject:val];
}
[val release];
[keys release];
return [NSArray arrayWithArray:pushArr];
}
#end
What is wrong with the code? Also app is crashing for this line of code
application is crashing if i include this line
NSArray *bgColor = [[NSArray alloc] initWithArray:[xmlObject fetchImmediateChildrenValues:[del.navigationbarStyle objectForKey:#"backgroundcolor"]]];
If I remove it application runs smoothly.
I have several comments on your code. One of them is the immediate cause of your crash, but you need to fix at least one other issue too. The short answer is that you over release val and keys.
NSArray *bgColor = [[NSArray alloc] initWithArray:[xmlObject fetchImmediateChildrenValues:[del.navigationbarStyle objectForKey:#"backgroundcolor"]]];
You don't need to create a new array here, you can simply write the following:
NSArray *bgColor = [xmlObject fetchImmediateChildrenValues:[del.navigationbarStyle objectForKey:#"backgroundcolor"]];
if you do, you don't need the [bgColor release] further down.
NSArray *keys = [[NSArray alloc] initWithArray:[tmp allKeys]];
keys = [keys sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
These two lines leak the first NSArray, you alloc it but you overwrite it straight away with the sorted version. In fact, you can simply write:
keys = [[tmp allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
Note that you do not own keys so you can get rid of the [keys release] line further down.
NSString *val = [[NSString alloc] init];
for(NSString *str in keys) {
val = (NSString *)[[tmp objectForKey:str] objectForKey:#"innertext"];
[pushArr addObject:val];
}
[val release];
This is the source of your immediate problem. You first alloc a new string. Then you immediately overwrite it on each iteration of your loop. So the allocated NSString leaks. You do not own the val returned by [[tmp objectForKey:str] objectForKey:#"innertext"]; on each iteration, so the release ov val after the loop should not be there.
On a side note, objectForKey: returns an id - the cast to NSString* is redundant. Most people leave it out.
[keys release];
Going back to the bit above where I told you that you were leaking your alloc'd keys? Well the new version of keys you overwrote it with you don't own. Therefore you must not release keys here.
return [NSArray arrayWithArray:pushArr];
This is fine. My preference would be for:
return [[pushArray copy] autorelease];
but it is just a matter of style. You could also just return pushArray, but pushArray is mutable and the caller may rely on the return value being immutable.
Test your code with NSZombieEnabled set... It should give you enough informations to fix your problem.

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.

Table crashes when sorting the data multiple times

I have a tableview with a navigationBar with a segmentedControl on the top of the view. I have set up the segmentedControl with buttons that sort the table by either "FirstName" or "LastName". It works perfectly the first 2-4 of times you press the sorting buttons, but then the app crashes.
The debugger and console seem to be of no help finding the source of the bug. Does anyone see any glaring mistakes in my code?
Here is my code below, let me know if you have any questions. Thanks!
- (IBAction)sortingSegmentAction:(id)sender{
NSString *keyToSortBy = [NSString alloc];
if([sender selectedSegmentIndex] == 0)
{
self.sortingSegmentActionPressed = 0;
keyToSortBy = #"FirstName";
}
else if([sender selectedSegmentIndex] == 1)
{
self.sortingSegmentActionPressed = 1;
keyToSortBy = #"LastName";
}
//Create the sort descriptors
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:keyToSortBy ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
//Sort allSubItams by the values set in the sort descriptors
NSArray *sortedArray;
self.sortedArray = [allSubItems sortedArrayUsingDescriptors:sortDescriptors];
//Recreate the data structure by putting the newly sorted items into a dictionary sorted by inital letters.
NSDictionary *eachItemList; //A DICTIONARY FOR PUTTING ALL THE DATA FOR EACH ITEM IN IT'S OWN SECTION
NSMutableDictionary *tempSectionedDictionaryByFirstLetter = [[NSMutableDictionary alloc] init];
for (eachItemList in sortedArray) //eachElementList is a dictionary with a section for each item
{
NSDictionary *aDictionary = [[NSDictionary alloc] initWithDictionary:eachItemList];
NSString *firstLetterString;
firstLetterString = [[aDictionary valueForKey:keyToSortBy]substringToIndex:1];
NSMutableArray *existingArray;
if (existingArray = [tempSectionedDictionaryByFirstLetter valueForKey:firstLetterString])
{
[existingArray addObject:eachItemList];
} else {
NSMutableArray *tempArray = [NSMutableArray array];
[tempSectionedDictionaryByFirstLetter setObject:tempArray forKey:firstLetterString];
[tempArray addObject:eachItemList];
}
[aDictionary release];
[eachItemList release];
}
//Set the data source for the table (sectionedDictionaryByFirstLetter) to tempSectionedDictionaryByFirstLetter.
self.sectionedDictionaryByFirstLetter = tempSectionedDictionaryByFirstLetter;
NSMutableArray *keyArray = [[NSMutableArray alloc] init];
[keyArray addObjectsFromArray:[[self.sectionedDictionaryByFirstLetter allKeys] sortedArrayUsingSelector:#selector(compare:)]];
self.keys = keyArray;
[self.tableView reloadData];
[keyArray release];
[tempSectionedDictionaryByFirstLetter release];
}
Don't release eachItemList at the end of your loop. You did not explicitly allocate it in this context so you shouldn't release it.
The for (object in array) loop gives you a reference to the object in the array, not a copy. By sending a release message to this reference, you are decrementing the retain count of this object while it is still in the array. After a few times (depending on how many times the object has been retained, NSArray for example retains objects when they are added to the array) it's retain count will reach 0, and it will then become deallocated and you'll get crashes regarding unrecognised selectors or EXC_BAD_ACCESS and possibly other kinds of errors.