Dictionary retrieval of value for key IOS - objective-c

I am sorry i am new to IOS,i couldnt figure out the solution to this problem
This is just a beginner restaurant menu
There is a tableview containing items and price and when i click one item,it displays another view where the user has to input the quantity and click a done button,so when the user clicks done i want to multiply the quantity times the price,how do i retrieve that particular price and multiply it with the quantity user input in the textfield.
Here's my code
I have declared NSDictionary in the Menu header file called
NSDictionary *dict;
My viewdidload method
dict=[[NSDictionaryalloc]initWithObjectsAndKeys:
#"TomatoSoup",#"20.00",#"VegManchowSoup",#"12.00",nil];
NSLog(#"%#",dict);
[super viewDidLoad];
I have displayed this contents in a table view
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section{
return [[dict allKeys]count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
NSArray *sortedkeys=[[dict allKeys]sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
NSString *key=[sortedkeys objectAtIndex:indexPath.row];
NSString *value=[dict objectForKey:key];
cell.textLabel.text=value;
cell.detailTextLabel.text=key;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath{
if(indexPath.row==0){
VegQuantity *vegetarian1 = [[VegQuantity alloc] initWithNibName:#"VegQuantity" bundle:nil];
vegetarian1.m_SelectedIndexPath=indexPath.row;
vegetarian1.pass=dict;
[self presentModalViewController:vegetarian1 animated:YES];
}
if(indexPath.row==1){
VegQuantity *vegetarian1 = [[VegQuantity alloc] initWithNibName:#"VegQuantity" bundle:nil];
vegetarian1.m_SelectedIndexPath=indexPath.row;
[self presentModalViewController:vegetarian1 animated:YES];
}
}
VegQuantity.h
There is a View that has a textfield and a button saying done,
now when I click the done button I need to retrieve the value for that particular soup and multiply it with the number of quantity I input.
My problem is how am I supposed to retrieve the price(value) for that particular key and multiply it with the quantity.

dict=[[NSDictionary alloc]initWithObjectsAndKeys:
#"TomatoSoup",#"20.00",#"VegManchowSoup",#"12.00",nil];
The method is initWithObjectsAndKeys, which means first is the object then key, (key "20.00", object - "TomatoSoup") - in your case it's the opposite.
Second, instead of having an NSString for the price (I suppose it's price or quantity) use NSNumber - [NSNumber numberWithFloat:20.0f].
Then, make your VegQuantity view controller (btw it's good idea to call it VegQuantityViewController, in order to keep the naming conventions) 2 properties:
#property (nonatomic, strong) NSString *itemName; //Use strong if using ARC, otherwise retain
#property (nonatomic, strong) NSNumber *price;
and pass those values to the view controller before you show it. Then inside it you can do whatever you want with them.
P.S. It's a good practice to use properties to manipulate the values of the instance variables.

You retrieve a value from a Dictionary by using.
[dict objectForKey:#"someDummyKey"];
But to be honest. You should use a NSMutableArray as datasource for you UITableView and not a NSDictionary.

Related

Issues using NSIndexPath as key in NSMutableDictionary?

Is there any particular reason why attempting to store and retrieve a value in an NSMutableDictionary using an NSIndexPath as a key might fail?
I originally attempted to do this in order to store an NSMutableDictionary of UITableViewCell heights (self.cellHeights) for a UITableView. Each time you tapped a UITableViewCell, that cell would either expand or contract between two different heights based on the value stored in the NSMutableDictionary for that particular indexPath:
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSNumber *heightNSNumber = [self.cellHeights objectForKey:indexPath];
if (!heightNSNumber)
{
heightNSNumber = [NSNumber numberWithFloat:100.0];
[self.cellHeights setObject:heightNSNumber forKey:indexPath];
}
return [heightNSNumber floatValue];
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSNumber *heightNSNumber = [self.cellHeights objectForKey:indexPath];
if (!heightNSNumber)
{
heightNSNumber = [NSNumber numberWithFloat:100.0];
[self.cellHeights setObject:heightNSNumber forKey:indexPath];
}
if ([heightNSNumber floatValue] == 100.0)
{
[self.cellHeights setObject:[NSNumber numberWithFloat:50.0]
forKey:indexPath];
} else {
[self.cellHeights setObject:[NSNumber numberWithFloat:100.0]
forKey:indexPath];
}
[tableView beginUpdates];
[tableView endUpdates];
}
For reasons unknown to me, getting the cell height within tableView:didSelectRowAtIndexPath: via [self.cellHeights objectForKey:indexPath] works just fine. However, trying to get the cell height within tableView:heightForRowAtIndexPath: via [self.cellHeights objectForKey:indexPath] always returns nil because it seems that the indexPath used to store the height doesn't match the indexPath being used to fetch the cell height, even though they have the same values for indexPath.section and indexPath.row. Because of this, a new object for the "same" index path is added to self.cellHeights (as evident since self.cellHeights.count increases thereafter).
This does not happen when you store the cell heights in the NSMutableDictionary using the row ([NSNumber numberWithInteger:indexPath.row]) as the key...so that's what I'm doing for now, but I'd like to understand why indexPath isn't working as the key.
Although I'm late in the discussion, here's a quick and simple solution that will allow you to use NSIndexPath instances as dictionary keys.
Just recreate the indexPath by adding the following line:
indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
VoilĂ . tableView:heightForRowAtIndexPath: uses NSMutableIndexPath instances internally (as you would see with a breakpoint). Somehow those instances seem uncooperative with NSIndexPath when calculating hash keys.
By converting it back to an NSIndexPath, then everything works.
#Jean's answer seems acceptable, but this question has been answered in more detail here. In short, UITableView sometimes uses instances of NSMutableIndexPath instead of NSIndexPath and instances of these two classes are never equal because [NSMutableIndexPath class] != [NSIndexPath class]. The workaround is to always generate a key NSIndexPath for anything that relies on isEqual or hash, such as looking up dictionary keys:
- (NSIndexPath *)keyForIndexPath:(NSIndexPath *)indexPath
{
if ([indexPath class] == [NSIndexPath class]) {
return indexPath;
}
return [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
}
There are several things that must be implemented for an object to work reliably as a key for NSDictionary, namely isEqual:, hash and Copyable protocol.
I am not very sure that NSIndexPath was ever intented to work as a key for dictionaries (because it was made to be an index for arrays).
My guess is that hash is not implemented correctly for different instances of the class. Also note that some of the table delegate methods are called with NSIndexPath and some with NSMutableIndexPath. That's probably making the difference.

How can you fill a UITableView with data from two arrays of two different object types?

Currently I fill a UITableView using this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CharNameCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
MyObject *obj = (MyObject*)[self.characters objectAtIndex:indexPath.row];
cell.textLabel.text = obj.name;
return cell;
}
But what could one do if you had two different arrays from two different types and you wanted to display a property from each in the cells?
Pseudocode:
MyObject1
MyObject2
cellTextLabel.text = Myobject1.name;
cellTextLabel.text = MyObject2.name;
Assuming that each object has a name property. I know my syntax above isn't correct, but I think you should get the drift.
I would suggest then that you store all of your objects in an NSMutableArray. This will be your data model. Then you can just iterate through the array to display the data in the UITableView. If need be, use introspection to find out what kind of class your object is.
id currentObject = [myArray objectAtIndex:indexPath.row];
if ([currentObject isKindOfClass:[MyObject1 class]]){
//set properties or do stuff with MyObject1
}else if ([currentObject isKindOfClass:[MyObject2 class]]){
//do stuff with Object2
}
This is just one suggestion. There are many ways to do this, but it will all depend on your app and what kind of persistence you are using, etc. Hope this helps.

Adding data to a tableView using a NSMutableArray

I'm having a problem adding an item to my tableView.
I used to initialize an empty tableView at the start of my App and get it filled with scanned items every time the tableView reappears and there is an item in my variable.
Initialization of the tableView:
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:nil];
self.listArray = array;
TableView Data Source:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.listArray count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if(section == 0)
return #"Eingescannte Artikel:";
else
return nil;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"testCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
NSUInteger row = [indexPath row];
cell.textLabel.text = [listArray objectAtIndex:row];//[NSString stringWithFormat:#"Das ist Zeile %i", indexPath.row];
return cell;
}
(Not the whole thing but the ones I changed)
As you may have seen I use an NSMutableArray to add items to my tableView.
So if an item ist scanned I'm adding it to my array like this:
[listArray insertObject:sharedGS.strEAN atIndex:0]; //using a shared Instance where I implemented my variable.
I also tried to use an variable to extend my Index every time a new Item is added, but it won't work both ways.
I'm quite new to programming so an not-too-hard-to-understand-answer would be quite nice ;)
If there's any information missing, feel free to ask.
/edit: Trying to specify my question: The data from the variable is written in a TableViewCell, but if I scan another one the other one is just being replaced. Not sure if it's a problem with my array or my tableView...
/edit No.2: Found out(thanks to fzwo) that my array isn't working correctly. It just doesn't grow by an addObject: or insertObject:atIndex: command. But I just don't get why... :(
All I'm doing: [listArray addObject:sharedGS.strEAN]; not that much space for errors in one simple line. Maybe I'm just too stupid to recognize what I'm doing wrong:D
You state that your problem is "adding an item to my tableView" , since you are adding the object to your array i am guessing the problem is that you are not reloading the table or that it is missing the dataSource binding.
You have not actually asked any question (even if you added info to "specify your question") so a wild guess, after
[listArray insertObject:sharedGS.strEAN atIndex:0];
put
[yourTableView reloadData];
Are you intentionally adding new items to the top of the table ? otherwise you could do
[listArray addObject:sharedGS.strEAN]; to add new items to the bottom
Otherwise it's worth noting that you are misusing dequeueReusableCellWithIdentifier, look at the example below for proper usage:
// Try to retrieve from the table view a now-unused cell with the given identifier
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
// If no cell is available, create a new one using the given identifier
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}

How to passing a NSMutableArray to another ViewController class

I have created NSMutale Array in "HeroListViewController". I want use it in another viewController which is MapTutorialViewController. I tried like this.
in HeroListViewController.h
MapTutorialViewController *maptutorialcontroller;
NSMutableArray *listData;
set properties and synthesize them correctly
in HeroListViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
listData = [[NSMutableArray alloc] init];
}
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *HeroTableViewCell = #"HeroTableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:HeroTableViewCell];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:HeroTableViewCell] autorelease];
}
NSManagedObject *oneHero = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSInteger tab = [tabBar.items indexOfObject:tabBar.selectedItem];
switch (tab) {
case kByName:
cell.textLabel.text = [oneHero valueForKey:#"name"];
cell.detailTextLabel.text = [oneHero valueForKey:#"secretIdentity"];
break;
case kBySecretIdentity:
cell.detailTextLabel.text = [oneHero valueForKey:#"name"];
cell.textLabel.text = [oneHero valueForKey:#"secretIdentity"];
default:
break;
}
[listData addObject: [oneHero valueForKey:#"secretIdentity"]];
count=[listData count];
printf("No of items of listData:%u\n", count);
if(maptutorialcontroller==nil){
maptutorialcontroller= [[MapTutorialViewController alloc]initWithNibName:#"MapTutorialViewController" bundle:nil];
maptutorialcontroller.secondarray=listData;
}
count=[maptutorialcontroller.secondarray count];
printf("No of items of seconarray :%u\n", count);
return cell;
}
OUTPUTS : No of items of listData:3
No of items of seconarray :3 // both are correct
BUT the the problem I have, when I try to use the secondarray in "MapTutorialViewController" like this,
in MapTutorialViewController.h
HeroListViewController *heroviewcontroller;
NSMutableArray *secondarray;
set properties and synthesize them correctly
in MapTutorialViewController.m
- (void)viewDidLoad
{
heroviewcontroller = [[HeroListViewController alloc]initWithNibName:#"HeroListViewController" bundle:nil];
self.secondarray=[heroviewcontroller.listData mutableCopy];
//secondarray= heroviewcontroller.listData;
int count;
count = [secondarray count];
//
printf("No of items of secondarray from MapTutorialViewContriller :%u\n", count);
}
OUTPUT : No of items of secondarray from MapTutorialViewContriller :0
Why it is 0
whats the wrong with my code, please help me
Example
firstviewcontroller .h file
before #interface
use #class secondViewcontroller;
declare this inside of #interface with
secondViewcontroller *sVC;
then in firstViewController.m file
before #implementation
#import "secondViewcontroller.h"
then
-------------------
secondVC.h file
#interface inside declare this
say NSMutableArray *secondarray;
and sythasize them.
-------------------
after this
in firstViewcontroller.h viewdidload create this sVC by alloc and initwithnibname then
sVC.secondArray=urfirstArray;
now while u push this sVC controller to navigation controller u can nslog this array in viewdidload.
This would only work if you create and fill the mutable array in the init method.
You should look into delegation and/or notification.
How is that array being created within HeroListViewController? In this method, you are creating a NEW instance of HeroListViewController and trying to get a property from it. If you already have a HeroListViewController in memory, this is completely wrong.
Make a property on the class for this viewDidLoad method. It should be of type NSMutableArray. When you allocate and initialize this class, call [set myArray:heroListArray] on it from HeroListViewController. That should give you access to it.
I'm assuming that you have a view containing this new view and the hero list view. If that is the case, then you could create a property in the new view like so:
#property (nonatomic,retain)HeroListViewController *heroListViewController;
and then set it equal to the heroList from the outside:
newView.heroListViewController = HeroListViewController;
The main problem with your code at the moment is that you're creating a new instance of HeroListViewController by using alloc init, and you're not accessing the same thing. By setting the new view's heroListViewController property, you can get access to the correct viewController.
Finally, in viewDidLoad of the new view - I'd actually put the code in viewWillAppear:(BOOL)Animated - you can put code to match the arrays.
Note that this whole way of doing it is messy and could be better done with a singleton class if you need access to an array in multiple places. The above will help you get it working quick, but if you want a really clean fix, go here: http://www.iphonedevsdk.com/forum/iphone-sdk-tutorials/24135-singleton-classes.html

setting UITableViewCell to value from custom object instance

So basically I am trying to create instances of the class below every time I received a valid response from a web request and then store those instances in an array so I can access their data later. Then, I try to populate a table view with specific fields from the instance(s) that are stored in the array. I've been having some issues since I am very familiar with C++ and do this sort of thing with vectors and then just access based off of the index I need, but this has had me pulling my hair out! Thanks, code is below:
eventDetails.h:
#interface eventDetails : NSObject {
NSString *eventName, *eventID;
}
-(void) setEventID : (NSString *) ID;
-(void) setEventName: (NSString *) name;
-(NSString *) getEventName;
-(NSString *) getEventID;
and also note that
NSMutableArray *events
is declared in my .h file and
events = [[NSMutableArray alloc] init];
has been called in the viewDidLoad
I then dynamically create instances as a response is received from an web request and add them to an array:
if ([elementName isEqualToString:#"id"])
{
NSLog(#"at beginning of event, length is %i", [events count]);
temp = [[eventDetails alloc] init];
[temp setEventID:[NSMutableString stringWithString:soapResults]];
[soapResults setString:#""];
elementFound = FALSE;
}
if ([elementName isEqualToString:#"name"])
{
[temp setEventName:[NSMutableString stringWithString:soapResults]];
[events addObject:temp];
[soapResults setString:#""];
elementFound = FALSE;
//[temp release];
}
After everything is all said and done, I created a little test function to ensure the data was set correctly:
-(void) test{
for (eventDetails *s in events){
NSLog(#"Entry ID: %# with name %#", [s getEventID], [s getEventName]);
}
}
and I get the following (correct) output:
2011-04-09 18:53:24.624 Validator[90982:207] Entry ID: 701 with name iPhone Test Event
2011-04-09 18:53:24.625 Validator[90982:207] Entry ID: 784 with name Another iPhone Test Event
2011-04-09 18:53:24.626 Validator[90982:207] Entry ID: 839 with name third iphone
I then try to refresh the table view, and have it pull in data from the instances in the array:
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
//---try to get a reusable cell---
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//---create new cell if no reusable cell is available---
if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}
//---set the text to display for the cell---
eventDetails *cellDetails = [[eventDetails alloc] init];
NSInteger row = [indexPath row];
cellDetails = [[self events] objectAtIndex:row];
NSString *cellValue = [cellDetails getEventName];
NSLog(#"Event is: %#", cellValue);
cell.textLabel.text = cellValue;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
return cell;
}
But every time the program gets to this part, it crashed which a EXC_BAD_ACCESS where I say:
cell.textLabel.text = cellValue;
Thanks for your help. I think I might be doing something wrong with how I declare the instances of the eventDetails class, but I am not sure since it is working correctly as far as storing that data. If you need any more code, I have the missing sections.
There are too many omitted details in the code you posted to know for sure, but my guess would be the eventName isn't retained, and is deallocated sometime before you attempt to use it.
Check your setEventName: implementation; it would need to send either retain or copy to the name argument to ensure that the string won't be deallocated before you're done using it. However, the situation is more complex than that if you want to avoid memory leaks, so you if you haven't done so already, I'd recommend reading up on memory management, in particular, Apple's excellent Memory Management Programming Guide. (Note: I've given up posting links since Apple keeps changing them).
A side note: don't prefix the names of accessor methods with the word get; that would be fine in Java or C++, but this is Objective-C. Your accessors should look like this:
- (NSString *)eventName;
- (NSString *)eventID;
There's no guarantee that Foundation mechanisms that rely on introspection will work correctly with accessors that don't follow the documented naming conventions, so that's another thing to read up on. :-)