problems with deleting a cell of a table - iphone

in my table (UITableView) I use cells with a UITextField istead of UILabel, added to the cell by "addSubview". I need this, because I want my cells to become directly be editable. As cell-style I use UITableViewCellStyleDefault. - Everything works fine: I can add and edit cells whenever I want.
However, deleting makes a problem: When I "delete" a cell and make a reloadData ot the table, the cell still displays its old content, together with the new one. Also the same for all cells below it. When I close my app and start it again, the table is displayed correctly.
Here the code I use to delete the cell
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = [indexPath row];
NSUInteger count = [datas count];
if (row <= count) {
NSString* data = [datas objectAtIndex: [indexPath row]];
[self deleteDatas:data];
}
[self.locationTable reloadData];
}
Where in deleteDatas I just delete the corresponding datas from a file, which works correctly, as "prooved" by new loading the app.
Here
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPress:)];
longPressGesture.minimumPressDuration = 2.0;
[cell addGestureRecognizer:longPressGesture];
}
// Configure the cell.
// table cell with uitextfield instead of lable.
UITextField* textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 185, 30)];
textField.enabled = NO;
[cell.contentView addSubview:textField];
NSUInteger count = [datas count];
NSUInteger row = [indexPath row];
// last cell is empty to edit it
if (row+1 < count) {
textField.text = [datas objectAtIndex:[indexPath row]];
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
return cell;
}
Any idea? - Thanks
Any idea, why my cell shows twice the content (once of the original cell and once the content of the cell below?) - I think s.th. is wrong with reloading the cell. - Is it possible that the textfield makes problems? - How can I figure this out?

You should probably write your commitEditingStyle: method more like this:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
if (indexPath.row <= [data count]) {
// Update the model by deleting the actual data
NSString* data = [datas objectAtIndex:indexPath.row];
[self deleteDatas:data];
// Delete the row from the table
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom];
}
}
}
Other things to check, are that your method for tableView:numberOfRowsInSection: returns the correct data, if it doesn't, then you'll get assertion failures when the table tries to remove rows, and the logic doesn't add up.

I think you should also remove the element from your mutablearray, in commitEditingStyle...
NSString* data = [datas objectAtIndex: [indexPath row]];
[self deleteDatas:data];
[datas removeObjetAtIndex: [indexPath row]];
Otherwise at your next reloadData the string is still there in memory and is displayed in cellForRow...

Related

Select multiple records from a table

I need to enable multiple selection in my tableview and also i need to keep track of what i have selected (like save it to an array or something). My approach so far;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text=[arrayobject objectAtIndex:indexPath.row];
bool xx = [[allmyselectedobjects objectAtIndex:indexPath.row] containsIndex:1];
if (xx) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}else{
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
return cell;
}
and the didSelectRowAtIndexPath method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.cuisineTableView cellForRowAtIndexPath:indexPath];
if ([cell accessoryType] == UITableViewCellAccessoryNone) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
[self.allmyselectedobjects insertObject:1 atIndex:indexPath.row];
}
else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
[self.allmyselectedobjects insertObject:0 atIndex:indexPath.row];
}
}
I could click multiple records, but when i scroll down i see other cells also ticked with the check mark (which i didn't select). I have been trying this for days now, can someone help me fix this code ?
A given cell instance is recycled and used for many rows. Store your checked indexPathes but not the cells.
Right before
Bool xx =
add this:
[cell setAccessoryType:UITableViewCellAccessoryNone];
It seems you are using an NSIndexSet to store checked cells. So just insert the index of the selected cell and test it.
// Test
BOOL xx = [allmyselectedobjects containsIndex: indexPath.row]
// Selected cell
[allmyselectedobjects addIndex: indexPath.row]
// Unselected cell
[allmyselectedobjects removeIndex: indexPath.row]

Load more cells "willDisplayCell" Problem

i have a problem with willDisplayCell it doesn't stop fetch Xml from the url
my code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [itemsToDisplay count] + 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if (indexPath.row == [itemsToDisplay count]) {
cell.textLabel.text = #"Load More...";
} else {
MWFeedItem *item = [itemsToDisplay objectAtIndex:indexPath.row];
cell.textLabel.text = item.title;
}
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == [itemsToDisplay count]) {
// Parse
NSURL *feedURL = [NSURL URLWithString:#"http://gdata.youtube.com/feeds/api/users/RayWilliamJohnson/uploads?v=2&alt=rss&sort_field=added&start-index=21&max-results=20"];
feedParser = [[MWFeedParser alloc] initWithFeedURL:feedURL];
feedParser.delegate = self;
feedParser.feedParseType = ParseTypeFull; // Parse feed info and all items
feedParser.connectionType = ConnectionTypeAsynchronously;
[feedParser parse];
[self.tableView reloadData];
}
}
its look like he is in kind of loop that doesnt stop fetch xml
so how can i fix it so i will only called once?
tnx
The problem is that you have called reloadData within tableView:willDisplayCell:. reloadData will cause every UITableViewCell to get drawn again, means willDisplayCell will get called for every cell that will be visible on screen. Seems to me like you have an infinite loop there.
tableView:willDisplayCell: is definitely the wrong place to be doing that XML parsing. willDisplayCell should just be used to prepare the UI. I can't say for certain, but perhaps a better place to the XML parsing would be in your view controller's init method.

UITableView cell/data disappear

I have a segmented tableView that loads all the data in all the cells of all the sections.
There is a textField in each cell.
The tableview doesn't fit the iPad screen completely, and I can't access all the invisible cells in order to read/save data. And when I make changes in "textField", then scroll up, the scroll down, all the changes are gone.
I need to load all the cells, even invisible once, to be able to access them.
I am sorry, I just started working with tables a few days ago...
I think that this problem has something to do with reusable cells, but not sure how to resolve it.
Looking for your help, please.
initialization:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 400, 30)] ;
textField.enabled = NO;
cell.accessoryView = textField;
[textField release];
}
UITextField *textField = (UITextField*)cell.accessoryView;
if(indexPath.section == 0)
cell.textLabel.text = [idenInfo objectAtIndex:indexPath.row];
else if (indexPath.section == 1)
cell.textLabel.text = [prodInfo objectAtIndex:indexPath.row];
else if (indexPath.section == 2)
cell.textLabel.text = [visInfo objectAtIndex:indexPath.row];
if(indexPath.section == 0)
textField.text = [idenInfoRez objectAtIndex:indexPath.row];
else if (indexPath.section == 1)
textField.text = [prodInfoRez objectAtIndex:indexPath.row];
else if (indexPath.section == 2)
textField.text = [visInfoRez objectAtIndex:indexPath.row];
textField = nil;
return cell;
}
First of all : you don't have to load all the cells including the invisible ones. That's the whole point of the UITableView and MVC Pattern : separate your views from your data.
What you'll want to do is update your Data source (that is idenInfoRez, prodInfoRez and vizInfoRez in your case) when the user has changed a value inside a textField. So you'll have to set your UIViewController as the delegate of each textfield and update the values as the user types in.
[UIView beginAnimations:#"ShiftUp" context:nil];
[UIView setAnimationDuration:0.0001];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger section = [indexPath section];
static NSString *CellIdentifier = #"Cell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = objCustCell;
cell.selectionStyle = UITableViewCellSelectionStyleNone ;
}
if (section == 0) {
switch (indexPath.row) {
case 0:{
cell.lable.text = #"Date of Birth";
cell.field.placeholder = #"Birth Name";
break;
}
case 1:{
cell.lable.text = #"Enter Your Name";
cell.field.placeholder = #"Full Name";
break;
}
default:
break;
}
}
[UIView beginAnimations:#"ShiftUp" context:nil];
[UIView setAnimationDuration:0.0001];
// [UIView beginAnimations: #"ShiftUp" context:nil];
NSLog(#"Load cellfor raw at index ");
// Configure the cell.
return cell;
}
Note : UIView animation will not allow text field to move away data or any UIcontroller will remain same in its old state !!
Don't Commit animation otherwise it will not working !!
What you can do is this: in the Editing Changed event of each of the TextField store the value contain in the text field in an NSMutableArray whose number equal the number of cells. i.e.
-(IBAction) EditingChanged: (id) sender
{
UITextField *txt =(UITextField*)sender;
NSString* str =[[NSString alloc] initWithString: txt.text];
//get current text string
NSInteger path =[tableView indexPathForSelectedRow].row;
// get currently selected row, this could be a bit different depending on the number of sections
[yourMutableArray insertObject: str atIndex: path];
[str release]
}
You can then populate the TextField with the values from the NSMutableArray anytime the cells are recreated i.e.
(UITableViewCell *) tableView: (UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath
{
...... // create the cells here and use viewTag to get the textFields
textField.text= [yourMutableArray objectAtIndex:indexPath.row];
//This may be a bit different depending on the number of sections.
}
Also, note that it might be advisable to initialize yourMutable array to the capacity of the number of cells.
I am sorry if the codes are not well formatted as this is my first post on stackoverflow - also there might be some typos in the code. Hope this helps someone.
every time we allocate the cell to different data,the data will not reloading the cell,every time the data override previous data, before allocate the cell to clear cell,
like as cell=nil
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell=nil;
//it clear data in the cell
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 400, 30)] ;
textField.enabled = NO;
cell.accessoryView = textField;
[textField release];
}
You're right, the problem is the cells will be reused. There are two solutions to the problem, the quick and dirty one would be to not use reusable cells:
Remove this:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
And just leave this:
UITableViewCell * cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 400, 30)] ;
textField.enabled = NO;
cell.accessoryView = textField;
[textField release];
That should be ok, if you have only a small number of cells in your tableview (about fewer than 50).
The better solution would be to leave cell reuse on, and fill their textfields as they are requested. The approach differs from app to app, but you basically never should access the cells directly, and store the data of the cell somewhere else, e.g. an NSArray of NSStrings. You could then manipulate the NSArray. Your cellForRowAtIndexPath method would look something like this:
textField.text = [arrData objectAtIndex:indexPath.row];

iPhone SDK: Making UITextField text in a custom UITableViewCell persist through scrolls?

I'm aware that to preserve memory usage, UITableViewCells are reused when scrolling. I have some custom UITableViewCells that have UITextFields in them. After text is inputted to the UITextField, and I scroll, that text is lost because of the cell reuse.
How can I make this text persist through scrolls? I'm thinking I can store each cell's text in its own index of an NSMutableArray. Then, when the cell is reused, I can repopulate it with the array data.
How would I go about doing this? Would someone be so kind as to post a code sample?
sample.h
#interface sample : UIViewController <UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate>
{
}
#end
sample.m
-(void)viewWillAppear:(BOOL)animated
{
arrData = [[NSMutableArray alloc]init];
for (int i=0; i<10; i++) // 10- number of fields
[arrData addObject:#""];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [arrData count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UITextField *txt = [[UITextField alloc]initWithFrame:frm];
txt.autocorrectionType = UITextAutocorrectionTypeNo;
txt.tag = indexPath.row;
txt.delegate = self;
txt.text = [arrData objectAtIndex:indexPath.row];
[cell addSubview:txt];
[txt release];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[arrData replaceObjectAtIndex:[textField tag] withObject:textField.text];
}

Populating cell in UITableView with unique items

I have an array of URL Links that I'm trying to load into a Grouped UITableView. The goal being that I have numberOfSectionsInTableView return [url count] so I can have number of sections equal to the number of url links. Then in numberOfRowsInSection returns 1 so I only populate 1 URL for each section.
The trouble I'm having is to ensure that cellForRowAtIndexPath won't keep grabbing the first url link. I suspect it's because it's always grabbing the first url because the rowIndex is always zero.
Any ideas how to ensure that each cell in my UITableView is populated with a different url link?
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [newsItems count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.numberOfLines = 5;
}
// Configure the cell. Get the title of the news item that was parsed out
int newsItemIndex = [indexPath indexAtPosition: [indexPath length] - 1];
[cell.textLabel setText:[[newsItems objectAtIndex: newsItemIndex] objectForKey: #"link"]];
return cell;
}
From what i see here you are making many sections with 1 row each...im not sure that ayou are getting the index correctly you can do something like this
int newsIntemIndex=indexPath.section
that should do it for you