Adding data to a tableView using a NSMutableArray - objective-c

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];
}

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;

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.

inserting UITableViewCell not working

Could somebody explain what I'm doing wrong in attempting to insert a new UITableViewCell? I'm trying to insert a custom UITableViewCell, but it throws the following error: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if (section == 0)
return 1;
else if (section == 1)
return numberOfRows;
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"EditableCell";
EditableCell *editableCell = (EditableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (editableCell == nil) {
editableCell = [[EditableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
_myTextField = [editableCell textFieldCell];
if (indexPath.section == 0){
[_myTextField setPlaceholder:#"Menu Name"];
[_myTextField setReturnKeyType:UIReturnKeyNext];
}
else if (indexPath.section == 1){
[_myTextField setPlaceholder:#"Category"];
[_myTextField setReturnKeyType:UIReturnKeyNext];
}
else {
[_myTextField setPlaceholder:#"Category"];
[_myTextField setReturnKeyType:UIReturnKeyDone];
}
_myTextField.keyboardType = UIKeyboardTypeDefault;
_myTextField.delegate = self;
return editableCell;
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
if (textField.returnKeyType == UIReturnKeyNext) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:1];
NSArray *array = [[NSArray alloc] initWithObjects:indexPath, nil];
[self.tableView insertRowsAtIndexPaths:array withRowAnimation:UITableViewRowAnimationTop];
numberOfRows = numberOfRows + 1;
[self.tableView reloadData];
}
}
You need to make sure that the number of rows returned in the method below now returns the correct number of rows.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
I am sure what is happening is that you are returning the same value here after your insert, whereas the runtime is expecting it to be one more than it was before you made the call to insert a row.
In a bit more detail, what is happening in MVC terms (Model/View/Controller) is this:
Your call to insertRowsAtIndexPaths is requesting that the Controller update the View with an additional row.
The Controller then does a sanity check to see if you have your sums right, so it calls:
tableView:numberOfRowsInSection
Now the controller knows what value this method returned last time (in your case, 1), and it also knows that you have requested to insert a row. There have been no delete calls, so it expects the next time it calls this method, the value should be (last time's value + rows inserted - rows deleted) = 2
If the Controller deems that you have things in order, it will then call cellForRowAtIndexPath (along with other methods) to get the actual cells for each of the rows in each section.
So for your problem, you need to keep track of the rows in your model - maybe in an array or an ivar with the count of rows available. Update your model by updaing this value as you add/delete rows before you make the call to insertRowsAtIndexPath, and then return this value when tableView:numberOfRowsInSection is called.
Additional tip:
If you wish to have your cell inserts/deletes to be animated, change your code to the below. Notice there is no call to reloadData anymore, instead the insert/reload is wrapped in begin/end update calls - The animated updates will occur after endUpdates due to the reloadSections call.
NSMutableIndexSet *sectionsToReload = [[NSMutableIndexSet alloc] init];
[sectionsToReload addIndex:1]; // Add sections as necessary
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:array withRowAnimation:UITableViewRowAnimationTop];
[self.tableView reloadSections:sectionsToReload withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
Check out the WWDC 2010 video from Apple, "Mastering Table Views" - explains everything really nicely, regarding using insertRowsAtIndexPaths and associated methods.
HTH,
Stretch
After you attempt to insert a new cell, your datasource must contain the number of original cells (1) plus the "extra" cell you are inserting (1) for a total of 2. So your tableView:numberOfRowsInSection: must return 2.
The error message indicated that tableView:numberOfRowsInSection: returned 1.
Update your datasource so that it returns this "extra" cell.

warning received at objectsAtIndexes

I am trying to fetch data from core data, it works fine. But when I try to fill a Table Cell then it gives me warning at the following line
cell.textLabel.text = [fetchedObjects objectAtIndex:indexPath.row];
Warning : passing argument 1 of 'objectsAtIndexes:' makes pointer from integer without a cast.
fetchedObjects is an NSArray object declared in header file. Kindly guide me where I am doing wrong. I can provide whole method for more understanding.
Regards.
EDIT
Here is my complete method code:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"] autorelease];
cell.textLabel.text = [fetchedObjects objectAtIndex:indexPath.row];
return cell;
}
Your posted code says you're calling objectAtIndex, which does indeed take an integer parameter. However, your error says you're using objectAtIndexes, which takes a pointer to an NSIndexSet. As indexPath.row is not an NSIndexSet pointer, you're getting that warning (saying that you're trying to use a raw integer as a pointer).
Check your actual code. Almost certainly, you're using objectAtIndexes by mistake.

Obj-C, have a number of tableviews, need to quickly add code to say not data found?

I have a number of views with UITableViews and I'd like to quickly add code to each so that I can add a row with a simple label saying that there was no data to be shown.
Whats making things a little bit more complicated is that in some cases I'm using custom cells.
I don't want to have to change my populate data array functions, but I can't think of a way to add this feature to a lot of tables quickly.
Can anyone show me what to do ?
In the tableView:numberOfRowsInSection: data source method, get the number of rows as normal. Then, if the number is 0, return 1 instead. In the tableView:cellForRowAtIndexPath: method, perform the same test. If there is no data, use a different cell and set it up for your message.
The following example assumes that you have 1 section and that your data is an NSArray instance variable named theArray which contains strings.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger num = theArray.count;
return (num ? num : 1);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
if(theArray.count == 0) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
cell.textLabel.text = #"No Data Found";
return cell;
}
// Normal processing here
}