I am populating a tableview from data that is received from a server. The data is a list of user activities within a given timeframe. One such activity is "Login". I do not wish to populate my tableview with this string but I'm not sure how to skip it when populating my tableview.
Here is how I populate the cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
#try{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *action = [object valueForKey:#"theActionName"];
if ([action isEqualtoString:#"Login"]) {
return cell;
}
return cell;
}#catch (NSException *ex) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
}
As you can see I tried using return cell but as you probably know it gives me a blank cell when the table is displayed. I'm sure there is a simple line of code for this but I came up blank with the search terms I used. Could someone please enlighten me! Thanks!
P.S. you may be thinking I am not putting anything in any of the cells but I pulled out a bunch of code to keep this short.
UPDATE:
Thanks for the heads up on "isEqualtoString:" Everything worked fine with "isEqual" but I changed it given that I received so many suggestions to do so. But this is not what I am asking.
To be more clear if I had an array containing the terms: view, view, login, view. When my tableview was populated I would have 4 cells that said; view, view, login, view. I simply want to ignore the term login so that I would have 3 cells that all said view. Thanks!
There can be many way to do this.
I Belive that UITabelView should display what its datasource (here datasource is self.fetchedResultsController) contains.
What you can do is create another NSArray from self.fetchedResultsController which does not contain this object.
Try this:
NSMutableArray *newSource = [[NSMutableArray alloc] init];
for(int i = 0; i < self.fetchedResultsController.count ; i++)
{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *action = [object valueForKey:#"theActionName"];
if (![action isEqual:#"Login"])
{
[newSource addObject:action];
}
}
[tableView reloadData];
Now use newSource instead of self.fetchedResultsController
You might think that using one more array is not good. But believe it it is far easier than using the same array with condition. You don't have to worry about that condition when you perform some operation with your UITableView like remove object by using indexpath.
try using if ([action isEqualToString:#"Login"])
When you want to compare strings you need to use this isEqualToString .
Change this line
if ([action isEqualToString:#"Login"]) {
return cell;
}
You are using the wrong function to compare your input string and the given data variable.
They both are NSString objects so use :
if([action isEqualToString:#"Login"])
{
//enter your code here
}
#Ben : I am assuming that you have registered you cell through nib as you are using dequeueReusableCellWithIdentifier.
Make your tableview content as "Dynamic prototype" (You can see this in Attributes Inspector of table view) and change your table view cell style as custom (You can see this in Attributes Inspector of tableview cell).
Related
I have my main view controller that shows a UITableView.
Each cell of this are custom (I've created a UIView for custom presentation).
For showing these items in my tableView, I populate an array with the content of the "allFilesFolderPath" folder with this code:
- (void)configureView {
_itemArray = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:allFilesFolderPath error:nil];
}
and
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.itemArray count];
}
and I create my custom cells for showing them with :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = [indexPath row];
myItem = [self.itemArray objectAtIndex:row];
NSLog(#"My Item : %#", _itemArray.description);
static NSString *CellIdentifer = #"cardCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifer];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifer];
}
return cell;
}
When I print the array with the NSLog, I get the correct list of item and in the alphabetical order (like how they are stored in the Documents location on my iPhone):
My Item : (
Music,
Music10,
Music2,
Music3,
Music4,
Music5,
Music6,
Music7,
Music8,
Music9,
Photos,
Videos
)
But when I run the app in my iPhone (or in the simulator), the cells are correctly displayed (in the order) until the eighth item. After this number, in my case, instead of having "Music8", "Music9", "Photos", "Video" I come back to the beginning of th array so "Music", "Music10", "Music2" and "Music3"
To better understand what I get, here is the screenshots :
I'm really lost! I've searched (and search again) what I'm doing wrong but I don't find anything, everything is correct for me.
Please help me to find my issue so that I can sleep normally.
EDIT: here is the method I've set to retrieve the myItem string from my other class :
+ (NSString *)getItemName {
return myItem;
}
And here is how I retrieve it from my other class :
NSString *test = [ViewController getItemName];
_itemName.text = test;
EDIT2 : Here is the code used for setting my custom TableViewCell
(sorry for missing these informations
#import "TableViewCell.h"
#implementation TableViewCell
- (void)awakeFromNib {
// Initialization code
[self cardSetup];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)cardSetup {
_cardView.layer.masksToBounds = NO;
_cardView.layer.shadowOffset = CGSizeMake(0, 1);
_cardView.layer.shadowRadius = 1;
_cardView.layer.shadowOpacity = 0.3;
NSString *test = [ViewController getItemName];
_itemName.text = test;
}
#end
There is this call named "dequeueReusableCell...". Table view cells are reused. If 8 cells fit on the screen, and you scroll the view up, your ninth row will reuse the cell that was used for the first row. That's why you have to set up your cell in cellForRowAtIndexPath, which apparently you refuse to do.
Cells are used just for display. They are not used for storing data. You should have a data model, accessed by everyone. cellForRowAtIndexPath reads from that data model. And then if something happens (for example by tapping on a button in a cell) that changes the data model, then you change the data model, and the data model should tell all the interested parties that the model has changed.
Your cell in one view and a UILabel elsewhere should definitely not be connected at all. Any changes should propagate through your data model.
You're not using myItem anywhere in cellForRowAtIndexPath: Your cells seem to be getting their text from some other method, when they should be getting it from celForRowAtIndexPath:
I am trying to get a URL from a cell. To do this, I am using NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; and then would like to do something like NSURL *url = self.finalURL[indexPath.row] but because indexPath.row is only for Arrays, this doesn't work. Is there a way to achieve the same thing as indexPath.row but for objects not in an array.
Here is how I am saving the url:
cell.finalURL = self.finalURL;
A cell doesn't have a URL, unless you create a subclass of the cell and add that property to is. Conventionally, you will have an array of objects, strings, dictionaries, etc., and that is your tableView's data source.
If I had an array with three NSURLs in it called myArray that contained google, amazon, and bing, and I wanted to display three cells with the respective labels matching the items in the array, I would implement the following code:
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// we only want a single section for this example
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// this tells the tableView that you will have as many cells as you have items in the myArray array
return myArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// first we try to reuse a cell (if you don't understand this google it, there's a million resources)
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
// if we were unable to reuse a cell
if (cell == nil) {
// we want to create one
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
// here is where we do ANY code that is generic to every cell, such as setting the font,
// text color, etc...
cell.textLabel.textColor = [UIColor redColor];
}
// here is where we do ANY code that is unique to each cell - traits that are based on your data source
// that you want to be different for each cell
// first get the URL object associated with this row
NSURL *URL = myArray[indexPath.row];
// then set the text label's text to the string value of the URL
cell.textLabel.text = [URL absoluteString];
// now return this freshly customized cell
return cell;
}
That, along with the rest of the default tableview code and setting up the array itself, results in the following:
When a user taps on a cell you can access the URL in the array and do something with it like so:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// first deselect the row so it doesn't stay highlighted
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// get the URL associated with this cell by using indexPath.row as an index on your
// data source array, if you tapped the first cell, it will give you back the first URL in your array...
NSURL *selectedURL = myArray[indexPath.row];
// do something with that URL here...
}
Think of your table view's data source as a bunch of little cubbies. You can create the data source in a million different ways, but once you have it you basically take the items and place them in numbered cubbies. Your table view create's itself based on what's in those cubbies, so to make the first cell it looks in the first cubbie, and so on, and later on when a user selects a cell from that tableview, all the table view does is tell you the cubbie number that was selected, and it's your job to use that information to retrieve the data from that specific cubbie and do what you need to with it. Hope that helps!
I was having troubles using the dequeue mechanism in my tableview, i have a custom cell with a uiTextField.
When a put some value on it and do a scroll, the value of the TextField goes to another cell.
Anybody can help me on it ?
Thanks guys.
Here is the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyPedidoItemCell";
PedidoItemCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
if (!cell) {
cell = [[PedidoItemCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Produto *produto = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.lblNome.text = produto.nome;
cell.lblCodigo.text = produto.codigo;
cell.lblFuncao.text = produto.funcao;
return cell;
}
When you call dequeueReusableCellWithIdentifier it may return a cell that has scrolled out of view but still contains data in the UITextField. If you don't clear the content of the UITextField or set it to the proper value for the row, you may see unwanted data.
The code you showed is using CoreData to load data for cell, but you mentioned that you don't store the data anywhere.
I suspect that the you are getting object with no data from your fetchedResultsController because you did not store any data.
So quite possibly the produto is nil and you are not setting any values on cell.
Eventually the cell you updated manually gets reused and you see the text again.
You need to first store the data that you typed into the UITextField before you can retrieve it from core data.
When parsing a local XML file i can see the data in console using NSLog. While in the simulator am getting only the plain table view without any data parsed from xml. Am not understanding where am missing it.
- (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.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
theLists = [app.listArray objectAtIndex:indexPath.row];
cell.textLabel.text = theLists.title;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
I think you are not reloading your table view.
after completing your parsing just reload your table view.
[reload tablename];
then check your table view delegates are calling or not after this method.
I think this will help you.
happy coding.
It seems you are reloading in the DidLoad.But After parsing and getting the data from xml, You have to reload that data with TableView.
[yourtableView reloadData];
Before doing thing, be sure that you have set Delegate and DataSource.
I think there are two expected reasons for that:
1- May be the number of sections and number of row are not set with the correct value.
2- may be you need to reload the table view data.
Please check these two methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 5; // or any number you want
}
I got the answer finally where i didn't properly connected the tableview controller class with corresponding controller. I followed the link Trouble making connections with story board
And finally it showed the data in the table view.
Hope this answer might help others. Thanks for all the people who gave their suggestions in this post.
Figured I should add this, if you are having trouble with data not showing up or loading.
Make sure your tableview delegate and data source are set to self.
So in the viewcontroller's viewDidLoad() function, make sure you add
tableView.delegate = self
tableView.dataSource = self
I initialize data in my table with an array in viewDidLoad and then add the data to the cell. This a standard way of doing it that I read in a book.
This is what I have:
- (void)viewDidLoad {
[super viewDidLoad];
//Create array and add data ("tableViewValues" is initialized in .h file)
tableViewValues = [[NSMutableArray alloc]init];
[tableViewValues addObject:#"$280,000.00"];
[tableViewValues addObject:#"$279,318.79"];
}
// Customize the appearance of table view cells.
- (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];
}
NSString *cellValue = [tableViewValues objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
return cell;
}
So when the view loads, those two currency values are in my table.
Now in another function, I populate a another array with different currency numbers depending on what the user enter in a textfield. How would I update my current table view and replace those values with the values in my other array? Can anyone help me? Thanks!
You can call
[self.tableView reloadData];
to reload all data, however, you will need to program a way to have the array that you want populate the table. Maybe you want your -cellForRowAtIndexPath to call a private method that conditionally picks the correct array.
You have to remove all values from your array then you have to call table reload data
// In the method where you will get new values
[tableViewValues removeAllObjects];
[tableViewValues add:#"new values"];
//reload table view with new values
[self.tableView reloadData];
I've had this problem many times and I always make the same mistake.
[self._tableview reloadData] works!
The question is the place where you populate the table.
I did it in -(void)viewDidLoad and the table was updated with the same data. Apparently nothing happens.
Update the content of your table view (plist, dictionary, array, whatever) in the same place where you call [self._tableview reloadData], just before.
THAT IS THE KEY!!!
Do a test:
#pragma mark - Actions
- (IBAction)refreshParams:(id)sender {
self.dictionary = nil;
[self._tableView reloadData];
}
You can see how disappear the tableview content when you push the refresh button. Obviously, this is an example. I use a dictionary to populate the table and a button to refresh the content.
You'd need to (release and) recreate same tableViewValues array and then call reloadData method on tableView like this:
[self.tableView reloadData];
This will work if you're on table view controller and self.tableView points to the table in question.
in that function, after assigning values to the new array, all you have to do is
[tableViewValues removeAllObjects];
tableViewValues = [[NSMutableArray alloc] arrayByAddingObjectsFromArray:newArray];
[self.tableView reloadData];
[self.tableView reloadData];
will help you for this.
In Swift,
tableView.reloadData() or self.tableView.reloadData(), where tableView is a property in your ViewController.