Search for object in NSMutableArray and change value for that object - objective-c

I have project where user can add some Items to TableView. My data source for this TableView are objects with 2 properties NSString * nameOfItem and NSNumber * numberOfItem. Is any possibility to check my NSMutableArray if it contain string #"someString" as property nameOfItem and if yes than change numberOfItem +1 ?
UPDATE:
I try to do it with for(...in...) but it works just when i have only one object in my NSMutableArray. If i have more objects there it create one new object and than change value to ++ on old one:
Here is some code what i tried:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSString*nameToCheck = [NSString stringWithFormat:#"%#", [self.ivc.objects objectAtIndex:indexPath.row]];
for (Items *itemNamed in self.ivc.shoppingList.items) {
if ([itemNamed.nameOfItem isEqualToString:nameToCheck]) {
[itemNamed setNumberOfItem:[NSNumber numberWithInt:[itemNamed.numberOfItem integerValue]+1.0]];
} else {
Items *item = [Items new];
[item setNameOfItem:name];
[item setNumberOfItem:#(1)];
[self.ivc.shoppingList.items insertObject:item atIndex:0];
}
I want to create new one only if is not yet in that list.
Any help appreciated.

I don't know something like this but you can use a NSDictionary instead of NSArray using the name property as a key. And if you don't want to do that, you can sort the array and make a binary search for element.

Related

Objective-C Update Array of objects

I have the following entry that updates a labels text with the value:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *row = [tableView dequeueReusableCellWithIdentifier:#"TICKET_ITEM"];
UILabel *itemDiscount = (UILabel *)[row viewWithTag:502];
itemDiscount.text = [[arrayOfItem objectAtIndex:indexPath.row]TICKET_ITEM_DISCOUNT];
return row;
}
My problem is that after the fact I have button that allows for setting the discount (which is initially 0). After adjusting a slider I want to be able to take that discount % and update itemDiscount.text with the new value. I figure the way I need to do this is to update the arrayOfItem TICKET_ITEM_DISCOUNT entry and then use reloadData. But how do I update just the single item in the array?
Check out Apple's documentation on NSArray.
There are a variety of methods that could solve your problem.
indexOfObject:
or
indexOfObjectPassingTest:
spring to mind.
To edit an NSArray you'll need to make a mutable copy of the array then assign it back again:
NSMutableArray *temp = [arrayOfItem mutableCopy];
//update your value here
arrayOfItem = temp;

TableView doesn't allow for 'section' in dictionary

I want to loop through a list of json items to use in my sectioned tableView. For this I would like to restructure the data to have a section->array setup, where array contains an array of sessions.
First of all, I don't know if this is the preferred way to go, there may be easier ways. I keep getting the error that I am not allowed to use 'section' as an identifier in the dictionary. Moreover, when I use something else than a 'section' the dictionary keeps getting overridden.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSString *day = _json[#"days"][3];
NSString *key;
NSUInteger count = 0;
NSMutableArray *sessionList = [[NSMutableArray alloc] init];
NSArray *timeslotsSorted = [[_json[#"schedule"][day] allKeys]
sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSArray *locationsSorted = [[_json[#"schedule"][day][timeslotsSorted[section]] allKeys]
sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
for (key in locationsSorted) {
NSDictionary *temp = _json[#"schedule"][day][timeslotsSorted[section]][key];
if ([temp isKindOfClass:[NSDictionary class]]) {
[sessionList addObject:temp[#"title"]]; //test array
count++;
}
}
_sessionDict = #{
section: sessionList
};
return count;
}
You are doing all the work to build your data structure in the wrong place. Lets say there are 10 sections in your data. This will call the tableView: numberOfRowsInSection method 10 times which makes this a pretty inefficient place to do much work. You will also have to implement the method that returns the number of sections to show, and the method to display each individual row.
I would build my data structures in the viewWillLoad method and then store it locallaly and reuse it in all the tableView methods.
First, this is what NSInteger is:
typedef int NSInteger;
You must wrap it into an object. Something like:
[NSNumber numberWithInteger:section]
And than add it to your dictionary.
i don't really know that your timeslotsSorted and locationsSorted contain right items, but lets say they do. I would recommend you to have this sorting before - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section and - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; are called.
Lets say, you received JSON, so you have to parse it as you do, and then call [tableView reloadData] or reload visible cells with animations.
and then your tableView data source methods will be called and you will do something like:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [sessionList count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSString* key = [self.sessionList objectAtIndex:section];
return [[self.secions objectForKey:key] count];
}
and don't forget to make strong properties for self.sections and self.sessionList

Retrieve data from text field

I have a text field in my app. I am trying to store whatever is entered into the text field in an array and display it in my root view controller (which is a table view) on click of a button.
The method for the button is as follows:
-(IBAction)addNewCountry:(id)sender
{
[rootViewController.details addObject:nameField.text];
NSLog(#"Country name is %#", rootViewController.details);
[self.navigationController pushViewController:rootViewController animated:YES];
[rootViewController.tableView reloadData];
NSLog(#"new country added");
}
details is the array declared in RootViewController
However, the text field text is not retrieved. Can anybody tell me what am i missing?
Change this
[rootViewController.details addObject:nameField.text];
to this
NSString *name = [NSString stringWithString: nameField.text];
[rootViewController.details addObject: name];
You cont directly insert your string data to your array, you need to store as a string
NSString *stringval = [NSString stringWithString: nameField.text];
then add it in to your string using addobject
[rootViewController.details addObject: stringcal];
Is your details array declared as NSMutableArray? It must be declared as an NSMutableArray in order for it to be modifiable. Also when you initialized the array did you add this after the allocation:
[details retain];

UITableView is not displaying Cell Style 2

I'm trying to display an array of dictionaries variable in the table Cell Style 2 which is what the Contacts App uses to display the information of the contact.
For some reason the cell style does not show up.
The array variable "arrayOfDictionaries_E" which has the following setup.
/// Dictionary 1
NSArray *dataArray = [NSArray arrayWithObjects: #"Host", hostname, nil];
NSArray *keysArray = [NSArray arrayWithObjects: #"Label", #"Data", nil];
NSDictionary *host_dict = [[NSDictionary alloc] initWithObjects: dataArray forKeys: keysArray];
/// Dictionary 2
NSArray *dataArray2 = [NSArray arrayWithObjects: #"IP", hostIP, nil];
NSArray *keysArray2 = [NSArray arrayWithObjects: #"Label", #"Data", nil];
NSDictionary *ip_dict = [[NSDictionary alloc] initWithObjects: dataArray2 forKeys: keysArray2];
// Storage into Array of Dictionaries
NSArray *dictionariesArray = [[NSArray alloc] initWithObjects: host_dict, ip_dict, nil];
I have tested that the array contains the 2 dictionaries and both dictionaries are populated.
So I'm having trouble with:
First, I want the all cells to use CellStyle2.
Second, I want each dictionary to be created in a new section. (like the the Contacts App, selectively bundle groups of items together)
So here comes the code in my implementation file. It is a UIViewController adopting the 2 UITableView protocols.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [arrayOfDictionaries_E count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary * dict = [arrayOfDictionaries_E objectAtIndex:indexPath.row];
cell.textLabel.text = [dict objectForKey:#"label"];
cell.detailTextLabel.text = [dict objectForKey:#"Data"];
return cell;
}
Find a screenshot of the current tableView here.
On the nib, I have linked the tableView outlet to the file's Owner and done likewise for the delegate and source. I have changed the Style to Grouped.
However as seen on the image above, when I run the program the cell doesn't display in the proper style specified also I don't know how to get each row to display in separate sections. --> I'm think of an Array > Array > Dictionary variable, to get to work, however I'm quite lost at the fact of how this can be implemented.
I'm still relatively new to Objective-c, so you may need to explain with actual code implementations, to demonstrate how I may achieve this.
Thanks in advance to taking the time to answer this question.
There are 2 problems which I think could be in your way:
You are using #"label" as the key when populating the cell, but #"Label" when populating the dictionary. The keys are case sensitive
You are using indexPath.row, this will only be 0 or 1 since you have 2 rows per section. You should be using indexPath.section since there is one section for each entry in your array.
I'm not sure what you do expect to see in rows one and two, though.
OK, I've had another look at your question and you seem to be making things a bit more complicated than they need to be. You appear to have a host name and an IP address that you want to display in two cells within a section, with the same labels in each part of the section.
Why not just have a single array of dictionaries, holding the name and IP address, then in cellForRowAtIndexPath pick the dictionary based on the section number, then based on the row number display the relevant item from the dictionary, and hardcode the label at that point?
By the way, the reason your cell style does not appear is because you are passing nil for the label due to the issue mentioned above, so it appears to only have a single label.

Can't get contents of file from a .plist file into an array

I'm trying to create a create a simple app where I have a TableView that should display the contents of a file. I have created a Table View in IB and dragged it's delegate and data source to the file's owner and I have manually created a .plist file with 1 array that have 2 items.
In my TableViewController.h i have declared an array.
NSArray * posts;
In my implementation file I have declared the required methods for UITableViewDataSource like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Returning num sections");
return posts.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// create a cell
UITableViewCell * post = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"post"];
// fill it with content
post.textLabel.text = [posts objectAtIndex:indexPath.row];
// return it
return post;
}
And in my ViewController 'viewDidLoad' method I try to add the content of my file to the 'posts' array like this:
- (void)viewDidLoad
{
NSString * postFile = [[NSBundle mainBundle] pathForResource:#"Posts" ofType:#"plist"];
posts = [[NSArray alloc] initWithContentsOfFile:postFile];
NSLog(#"%#", postFile);
NSLog(#"%i", posts.count);
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
NSLog(#"%i", posts.count); returns 0, despite that I have added values to my .plist file. And nothing is displayed in the table view.
Suggestions on how so solve this would be appreciated.
I think you need to reload your table after you've loaded your postFile NSArray. If your view controller is a UITableViewController, try adding the following line of code to the end of your viewDidLoad method:
[self.tableView reloadData]
(On an unrelated note, you should also make your call to the super class the first thing you do in the viewDidLoad method, hence the comment the xcode template gives you.)
Edit: Problem with count.
I think you also have a problem with your debugging. count isn't a property of NSArray, so you can't use the dot syntax with it. You should be sending a message to your NSArray instance i.e. [posts count].
Ok, it seems like Xcode 4 creates plists with Dictionary as it's root type. If you want to use an array you have to open the .plist file in another text editor (probably doable in Xcode too) and change < dict >< /dict /> to < array >.
Also, it wasn't necessary to use an array at all. This also worked:
// Changed my array to a dictionary.
NSDictionary * posts;
// Get the cell text.
NSString * cellText = [[NSString alloc] initWithFormat:#"%i", indexPath.row];
// fill it with content
post.textLabel.text = [posts valueForKey:cellText];