how to edit an NSMutableArray data? - iphone

I have this NSMutableArray
sections = [[NSMutableArray alloc] init];
[sections addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Electricity",#"Type",#"0",#"Count", nil]];
[sections addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Water",#"Type",#"0",#"Count", nil]];
[sections addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Mobile",#"Type",#"0",#"Count", nil]];
[sections addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Internet",#"Type",#"0",#"Count", nil]];
[sections addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Fixed Line",#"Type",#"0",#"Count", nil]];
and lets say a user choose to change Water count from 0 to 10 how to do that?

[[sections objectAtIndex:1] setObject:#"10" forKey:#"Count"];
One more thing. When you create objects with alloc+init, you should release them yourself. So for each NSMutableDictionary you have a memory leak (in your code).
Use either [[[NSMutableDictionary alloc] initWithObjectsAndKeys:..., nil] autorelease]; or [NSMutableDictionary dictionaryWithObjectsAndKeys:..., nil]; (of course, you can make something like for (NSMutableDictionary *dict in sections) [dict release]; later, but this looks ugly).

Related

Is there a way to shorten my CountryViewController.m without hard coding?

I would like to know if there's a way to shorten my CountryViewController.m because I will be adding another else if statement every time I add a new country.
I am using a UITableViews that pushes a new table view.
RootViewController.m
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
    
    ASIA = [[NSMutableArray alloc] init];
    EU = [[NSMutableArray alloc] init];
    [ASIA addObject: #"China"];
    [ASIA addObject: #"Japan"];
    [ASIA addObject: #"Korea"];
    [EU addObject: #"France"];
    [EU addObject: #"Italy"];
    [EU addObject: #"Switzerland"];
    self.title = #"Continent";
}
CountryViewController.m
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear: animated];
if ([self.title isEqualToString: #"China"]) {
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Beijing"];
[_listOfCities addObject: #"Hong Kong"];
}
else if ([self.title isEqualToString: #"Japan"]){
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Tokyo"];
}
else if ([self.title isEqualToString: #"Korea"]){
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Seoul"];
}
else if ([self.title isEqualToString: #"France"]){
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Paris"];
[_listOfCities addObject: #"Versailles"];
}
else if ([self.title isEqualToString: #"Italy"]){
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Rome"];
}
else if ([self.title isEqualToString: #"Switzerland"]){
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Bern"];
}
[self.tableView reloadData];
}
A simple way is to use a property list and include that as a bundle resource (i.e. just add it to your project).
For example, if your property list looks like this:
You can then load it with
countries = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"CountryData" ofType:#"plist"]];
and use it as a normal dictionary or array, i.e.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear: animated];
NSString* countryName = self.title;
NSDictionary* country = [countries objectForKey:countryName];
NSArray* cities = [country objectForKey:#"Cities"];
NSString* continent = [country objectForKey:#"Continent"];
_listOfCities = cities;
[self.tableView reloadData];
}
Plist files can be edited easily in XCode.

Using a nested NSMutableDictionary

simple question, I need to structure data in the following format:
UserID:
1 {
Name = Bob
Surname = Hope
}
2 {
...
I can used an NSMutableDictionary to add a single layer with keys, but I am unable to create a child associate with a certain key.
I have tried creating a mutable dictionary and assigning that to a key:
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
NSArray *keys = [[NSArray alloc] initWithObjects:#"Name", #"Surname", nil];
NSArray *details = [[NSArray alloc] initWithObjects:#"Bob",#"Hope", nil];
NSDictionary *person = [[NSMutableDictionary alloc] initWithObjects:details forKeys:keys];
[dic setValue:#"1" forKey:#"id"];
[[dic objectForKey:#"id"] setDictionary: person];
I think it is better to use an array of dictionaries, each dictionary representing a user.
NSMutableArray *users= [[NSMutableArray alloc] init];
NSArray *keys = [[NSArray alloc] initWithObjects:#"Name", #"Surname", nil];
NSArray *details = [[NSArray alloc] initWithObjects:#"Bob",#"Hope", nil];
NSDictionary *person = [[NSMutableDictionary alloc] initWithObjects:details forKeys:keys];
[users addObject:person];
u can also set the objects for dictionary in this way
[dic setObject:person forKey:#"id"];

-[__NSCFString objectForKey:]: unrecognized selector sent to instance

// Configure the cell.
cell.textLabel.text = [[self.drinks objectAtIndex:indexPath.row] objectForKey:#"Name"];
return cell;
The above code is generating this exception. What could be causing this and how can I fix it?
My Understand from Your question
You have array of drinks like
Drink *d1 = [[Drink alloc] init]
d1.name = #"Drink1";
d1.price = [NSNumber numberWithFloat:25.0];
Drink *d2 = [[Drink alloc] init]
d2.name = #"Drink2";
d2.price = [NSNumber numberWithFloat:35.0];
OR
NSArray *values1 = [NSArray arrayWithObjects:#"Drink1",[NSNumber numberWithFloat:25.0], nil];
NSArray *keys1 = [NSArray arrayWithObjects:#"Name",#"price", nil];
NSDictionary *d1 = [[NSDictionary alloc] initWithObjects:values1 forKeys:keys1];
NSArray *values2 = [NSArray arrayWithObjects:#"Drink2",[NSNumber numberWithFloat:55.0], nil];
NSArray *keys2 = [NSArray arrayWithObjects:#"Name",#"price", nil];
NSDictionary *d2 = [[NSDictionary alloc] initWithObjects:values1 forKeys:keys1];
self.drinks = [NSArray arrayWithObjects:d1,d2, nil];
[d1 release];
[d2 release];
From the above case
cell.textLabel.text = [[self.drinks objectAtIndex:indexPath.row] objectForKey:#"Name"];
the above statement is correct
You are getting exception means, You are inserting the objects into drinks array, that supports Key Value Pairs data and that is String Data.
I hope you are having like this
self.drinks = [NSArray arrayWithObjects:#"Drink1",#"Drink2", nil];
In this above case you have to go with
cell.textLabel.text = [self.drinks objectAtIndex:indexPath.row];
first try to determine what object is self.drinks,
then you can go finer depending if is an array with dictionaries?
do a log
[self.drinks objectAtIndex:0]
what do you see?

iphone: problem in NSMutableArray and NSMutableDictionary

Dont know whats wrong with this array
NSMutableArray *locations=[[NSMutableArray alloc] init];
NSMutableDictionary *aLocation=[[NSMutableDictionary alloc] init];
[aLocation setObject:#"26.8465108" forKey:#"lat"];
[aLocation setObject:#"80.9466832" forKey:#"long"];
[locations addObject:aLocation];
[aLocation removeAllObjects]
[aLocation setObject:#"26.846127990018164" forKey:#"lat"];
[aLocation setObject:#"80.97541809082031" forKey:#"long"];
[locations addObject:aLocation];
[aLocation removeAllObjects];
but every time I remove all objects from aLocations dictionary those values get deleted from locations array as well.
Please help me in this
This behaviour is correct and you can't reuse NSMutableDictionary as you do: NSMutableArray does not copy objects it contains - it just stores pointers to those objects. So if an object you added to array changes then array has pointer to that changed object.
To fix your code create NSMutableDictionary instance each time you need to add it to array (or create immutable dictionary if you actually don't need mutable object):
NSMutableArray *locations=[[NSMutableArray alloc] init];
NSMutableDictionary *aLocation= [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"26.8465108", #"lat",#"80.9466832" ,#"long", nil ];
[locations addObject:aLocation];
aLocation= [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"26.846127990018164", #"lat",#"80.97541809082031" ,#"long", nil ];
[locations addObject:aLocation];
NSMutableArray *locations=[[NSMutableArray alloc] init];
NSMutableDictionary *aLocation=[[NSMutableDictionary alloc] init];
[aLocation setObject:#"26.8465108" forKey:#"lat"];
[aLocation setObject:#"80.9466832" forKey:#"long"];
[locations addObject:aLocation];
[aLocation release];
NSMutableDictionary *aLocation1=[[NSMutableDictionary alloc] init];
[aLocation1 setObject:#"26.846127990018164" forKey:#"lat"];
[aLocation1 setObject:#"80.97541809082031" forKey:#"long"];
[locations addObject:aLocation1];
[aLocation1 release];
NSMutableArray *locations=[[NSMutableArray alloc] init];
NSMutableDictionary *aLocation= [NSMutableDictionary initWithObjectsAndKeys:
#"26.8465108", #"lat",#"80.9466832" ,#"long", nil ];
[locations addObject:aLocation];
aLocation= [NSMutableDictionary initWithObjectsAndKeys:
#"26.846127990018164", #"lat",#"80.97541809082031" ,#"long", nil ];
[locations addObject:aLocation];

crashed on iphone but not on simulator

It is really mind boggling to find out many differences between the iphone and the simulators. I spent several hours trying to figure out why my application ran on the simulator but crashed on my iphone device. It turns out the culprit is sortedArrayUsingDescriptors. Are there more get-you like this? Please share with me.
To share with you on the issue and the fixes:
Code crashed on iphone but not simulator
NSSortDescriptor* aDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"count" ascending:NO] autorelease];
NSArray* anNsArray = [[NSArray alloc] init];
NSArray* aSortedNsArray = [[NSArray alloc] init];
aSortedNsArray = [anNsArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:aDescriptor]];
The issue is on [NSArray arrayWithObject:aDescriptor];
The fixes are to create an Array to store it:
NSArray* descriptorArray = [[NSArray alloc] initWithObjects:countDescrp, nil];
aSortedNsArray = [anNsArray sortedArrayUsingDescriptors:descriptorArray];
NSSortDescriptor* aDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"count" ascending:NO] autorelease];
NSArray* anNsArray = [[NSArray alloc] init];
NSArray* aSortedNsArray = [[NSArray alloc] init];
aSortedNsArray = [anNsArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:aDescriptor]];
This is a wrong initialization mechanism, and if the code snippet is complete, your problem lies on the anNsArray object that's empty.
You also do not need to initialize the aSortedNsArray.
So it should be:
NSSortDescriptor* sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"count" ascending:NO] autorelease];
// Assume you return it as array of objects from a property or method
NSArray *array = [self objects];
NSArray *sortedArray = nil;
if ([array count] > 0) {
sortedArray = [array sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
}
// Then you check the sortedArray
if (sortedArray == nil || [sortedArray count] == 0)
[self somethingIsWrong];
arrayWithObject: (autoreleased) or initWithObject: (manual) is just a different way to allocate NSArray object. It won't cause crashes normally. Because what you care about is the sortedArray not retaining the descriptors array object.