In my application,I will be displaying only one row on the UITableView initially. I want to increase the rows as user loads the previous row with data(an uiimage, here). As now i'm returning value 1, in numberOfRowsInSection: method, since I don't know how to implement it in the required way. Please help.
My cellForRowAtIndexPath: method is
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CustomCellIdentifier = #"CustomCellIdentifier";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CustomCellIdentifier ] autorelease];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
for (id currentObject in nib){
if ([currentObject isKindOfClass:[CustomCell class]]){
cell = (CustomCell *)currentObject;
cell.viewController = self;
break;
}
}
}
if (j<15){
cell.imageView.image = nil;
if (count!=0)
{
#try{
NSInteger row = [indexPath row];
cell.imageView.image = [array objectAtIndex:row];
}
#catch (NSException* ex) {
NSLog(#"doSomethingFancy failed: %#",ex);
}
}
}
cell.showsReorderControl = YES;
return cell;
[array release];
}
that if condition and count is nothing but just for checking the correct functioning of the mutable array, 'array'.
You should read this documentation: http://developer.apple.com/iphone/library/documentation/UserExperience/Conceptual/TableView_iPhone/Introduction/Introduction.html
Have a look to the related samples as well.
Note: in your code [array release] won't be called since you've got a return statement just before it.
When you reach the cellForRowAtIndexPath at a certain indexPath, it means that row is being displayed. If you reach the last row you can insert a new row into the table. To do that, you just need to increase the count that will get returned by the tableView:numberOfRowsInSection function.
I'm guessing your numberOfRowsInSection function will look something like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return section==0 ? [array count] : 0;
}
So basically, inside cellForRowAtIndexPath, add the following code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
if([indexPath row]==[array count]-1) {
[array addObject:(NEXT_IMAGE)];
}
return cell;
}
You also need to refresh the table. One way is to just call reloadData on your UITableView, but the preferred way is to call beginUpdates/insertRowsAtIndexPaths/endUpdates on the table so that you can show a nice animation of the row being inserted.
Related
I was wondering if anyone knows how to solve this problem:
I have a UITableview, where the datasource can continue to grow. The issue is when I add elements to the data source, the table cells get messed up.
Each table cell has a text field where the user can enter data into it, but whenever I add data to the datasource the comments replicate to other cells.
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"ImageTableCell";
ImageTableCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
Picture *aPicture = (Picture *) [self.imageData objectAtIndex:[indexPath row]];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ImageTableCell" owner:self options:NULL];
cell = (ImageTableCell *)[nib objectAtIndex:0];
}
NSLog(#"comment %# index %d", aPicture.comment, [indexPath row]);
cell.cellImage.image = aPicture.picture;
cell.commentField.delegate = self;
cell.commentField.text = aPicture.comment;
cell.index = [indexPath row];
cell.tag = [indexPath row];
return cell;
}
self.imagedata is a NSMutabaleArray.
EDIT
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.imageData count];
}
-(void) reloadImages:(NSNotification *) aNotification {
self.imageData = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).currentUserData.images;
[self.imageTableView reloadData];
}
a screenshot http://www.mikerizzello.com/pic.png
Thanks
EDIT:
I think you might have a bad MVC pattern. Here's what I would do:
Take your custom cell, ImageViewCell, and make that class your textField delegate. Add a property for your custom Picture object, and set that in cellForRow...
Then, in your textFieldDelegate methods inside the custom cell class, you can change set the contents of your PictureObject there. I have a feeling that you're handling text input in the viewController, and the index of the data object in your array is getting mixed up and you're applying the comment field text to the wrong item in the array.
EDIT
I think it has something to do with cell reuse. The contents of your cell are not getting wiped out upon reusing a cell.
Try this block before you return the cell:
if (!aPicture.comment) {
cell.commentField.text = #"";
} else {
cell.commentField.text = aPicture.comment;
}
Have you try with
if (cell == nil) {
cell = (ImageTableCell*)[[ImageTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
Anyway you can also set different reuseIdentifier for each of cells but it will be bad idea, I would like to help you but i think need to run this project.
Please let me know if code above give better solution.
I am trying to populate
UITableView in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method with an array I have initialized in viewDidLoad method.
self.questionsArray = [NSArray arrayWithObjects:#"Q1",#"Q2",#"Q3",#"Q4",#"Q5",#"Q6",#"Q7",#"Q8",#"Q9",#"Q7",#"Q8",#"Q9",#"Q10",#"Q11"];
I understand how to implement various sections and reusing a cell with an identifier. As most of the examples I have seen, I tried like question.text = [NSString stringWithFormat:#"%d. %#", indexPath.row ,[self.questionsArray objectAtIndex:indexPath.row]];
But I am getting like
0. Q1 1. Q2 2. Q3 3. Q4 4. Q5 5. Q6 0. Q1 2. Q2 ....
Please help to load all questions (NSString) to my TableView. I messing up with indexPath.row. Its very difficult to understand. Any tips for best practices to handle indexPath effectively.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch (section) {
case 0:
return [self.questionsArray count];
case 1:
return 1;
default:
return 0;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
static NSString *QuestionCellIdentifier = #"QuestionCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:QuestionCellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"QuestionCell" owner:self options:nil];
}
cell = questionCell; // IBoutlet
self.questionCell = nil;
}
question.text = [NSString stringWithFormat:#"%d. %#", indexPath.row ,[self.questionsArray objectAtIndex:indexPath.row]];
return cell;
}
else if (indexPath.section == 1){
static NSString *CustomCellIdentifierMore = #"CustomCellIdentifierMore";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CustomCellIdentifierMore];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CustomCellIdentifierMore] autorelease];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
switch (indexPath.row) {
case 0:
cell.textLabel.text=#"Select";
break;
default:
break;
}
}
return cell;
}
return nil;
}
cellForRowAtIndexPath is not guaranteed to load cells in order and will be called to update certain cells. You also need to provide the numberOfRowsInSection method, for example:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.tableData count];
}
Are your cells displaying properly or is it just the nslog that is producing confusing output?
Try calling reloadData on your tableView after creating questionsArray in viewDidLoad, so like this:
self.questionsArray = [NSArray arrayWithObjects:#"Q1",#"Q2",#"Q3",#"Q4",#"Q5",#"Q6",#"Q7",#"Q8",#"Q9",#"Q7",#"Q8",#"Q9",#"Q10",#"Q11"];
//or whatever your property for the tableview is called.
[self.tableView reloadData];
Your cellForRowAtIndexPath implementation is a little funky. First, the curly brackets for indexPath.section == 0 condition don't match. Second, I don't see where you are setting the text for cell that you are returning. Whatever you are assigning to question.text should be assigned to cell.textLabel.text. Third, for indexPath.section == 1 condition, you are only setting the text when the cell is nil. The table view is pretty smart about cell management. When a cell goes out of view due to scrolling, it will reuse the cell instead of entirely creating a new one. So, whenever you deque a cell, it may not always be nil. So, you should be setting the cell text outside the if (cell == nil) loop.
So I don't know how this is happening, or how to fix it, but I am having an issue of my UISearchDisplayController's plain tableView displaying search results with a grouped cell.
I have a dataSource array with a few names, a tableData array that iterates through the dataSource array and adds any entries that fit the searchText, and then depending on which tableView it is, I reload the tableView with the appropriate dataSource...
Ideas anyone?
Code:
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
int count = 0;
if(aTableView == self.tableView){
count = [userTableData count]==0?1:[userTableData count];
}else{
count = [tableData count];
}
return count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return #"Users";
}
- (UITableViewCell *)tableView:(UITableView *)tView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}
if(tView == self.tableView){
if([userTableData count] == 0){
cell.textLabel.text = #"Please select a user";
}else{
cell.textLabel.text = [userTableData objectAtIndex:indexPath.row];
}
}else{
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
}
return cell;
}
And then as the search is entered, matching strings are added to the tableData array
assign tags to the UITableView and hide the grouuped tableView while searching
In the documentation for UISearchDisplayController about the searchResultsTableView property, it says
Discussion:
This method creates a new table view if one does not already exist.
So what you could try is create your own UITableViewwhen you set up the UISDC, explicitly making it plain:
UITableView *searchTableView = [[UITableView alloc] initWithFrame:CGRectZero
style:UITableViewStylePlain];
searchDisplayController.searchResultsTableView = searchTableView;
I am currently making a custom UITableView cell as shown below.
The custom UITableViewCell is in its own nib file that I am calling from another ViewController. (like so)
// RegistrationViewController.m
//Sets number of sections in the table
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
// Sets the number of rows in each section.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
//Loads both Custom cells into each section
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Registration Cell
static NSString *CellIdentifier = #"CustomRegCell";
static NSString *CellNib = #"LogInCustomCell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil];
cell = (UITableViewCell *)[nib objectAtIndex:0];
}
//Registration Button
static NSString *CellButtonIdentifier = #"CustomSubmitCell";
static NSString *CellButtonNib = #"LogInSubmitButton";
UITableViewCell *cellButton = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellButtonIdentifier];
if (cellButton == nil) {
NSArray *nibButton = [[NSBundle mainBundle] loadNibNamed:CellButtonNib owner:self options:nil];
cellButton = (UITableViewCell *)[nibButton objectAtIndex:0];
}
if (indexPath.section == 0) {
cell.selectionStyle = UITableViewCellSelectionStyleNone; //Stops the UITableViewCell from being selectable
[self registrationControll];
//TODO: call method that controls this cell
return cell;
}
if (indexPath.section == 1) {
cellButton.selectionStyle = UITableViewCellSelectionStyleNone; //Stops the UITableViewCell from being selectable
return cellButton;
}
return nil;
}
It has four text fields that I am wanting to limit the size of the string that can be entered to five. (I'm only trying it with the first text field so far but its not even entering the textField:shouldChangeCharactersInRange:replacementString: delegate method (found this out while debugging the app) here is the code for the part I am trying to restrict the amount of characters that can be entered.
// RegistrationViewController.m
//textField:shouldChangeCharactersInRange:replacementString:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
int length = [regFieldOne.text length] ;
if (length >= MAXLENGTH && ![string isEqualToString:#""]) {
regFieldOne.text = [regFieldOne.text substringToIndex:MAXLENGTH];
return NO;
}
return YES;
}
I think I have limited my error to one of two things.
Maybe I haven't set everything up in interface builder correctly.
OR it has something to so with delegation... which I have a general understanding of and is why I think the issue might be here, but with such a complex file structure I'm not sure how or if this is right.
Any help, explanations, suggestions etc would be greatly appreciated.
At some point, you need to set the delegate for the textField
Since you put the delegate method in RegistrationViewController.m, you can set the delegate right after adding the cell in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath.
As long as you are returning a subclass of UITableViewCell from LogInCustomCell.xib, you can use something like this:
LogInCustomCell *cell = (LogInCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil];
cell = (LogInCustomCell *)[nib objectAtIndex:0];
}
cell.textField1.delegate = self;
cell.textField2.delegate = self;
cell.textField3.delegate = self;
cell.textField4.delegate = self;
...
return cell;
From what I can see
You have the delegate methods in RegistrationViewController.m
But you are idnicating that CustomRegCell is the delegate, so the delegate methods should be there
I have a tableview displaying data using a custom UITableViewCell(say cell1). On touch of a row, I change the custom cell to another custom UITableViewCell(say cell2). Also I increase the size of row of the selected cell to accomodate, more items of cell2.
My problem is that the approach works fine when the number of rows in table view is less. When the number of rows increses, the rows expand on touching, but the data displayed is same as that of cell1. Cell2 doesn't seem to be loaded at all.
Looking forward for a reply soon....Thanks in advance.
I am posting my code....please let me know if there is a problem in that.
My cellForRowAtIndexPath looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath == selectedCellIndexPath)
{
static NSString *Identifier1 = #"Identifier1";
Identifier1 = #"cell2";
CustomCellController1 *cell = (CustomCellController1 *)[tableView dequeueReusableCellWithIdentifier:Identifier1];
if(cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"CustomCellController1View" owner:self options:nil];
cell = rowTwoObject;
}
[cell setText:[test1Array objectAtIndex:indexPath.row]];
return cell;
}
else {
static NSString *Identifier2 = #"Identifier2";
Identifier2 = #"cell1";
CustomCellController1 *cell = (CustomCellController1 *)[tableView dequeueReusableCellWithIdentifier:Identifier2];
if(cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"CustomCellController1View" owner:self options:nil];
cell = rowOneObject;
}
[cell setText1:[temp1Array objectAtIndex:indexPath.row]];
[cell setText2:[temp2Array objectAtIndex:indexPath.row]];
return cell;
}
}
didSelectRowAtIndexPath looks like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
selectedCellIndexPath = indexPath;
[tableView reloadData];
}
heightForRowAtIndexPath looks like this:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if(selectedCellIndexPath != nil
&& [selectedCellIndexPath compare:indexPath] == NSOrderedSame)
return 110;
return 60;