I have a View (SearchView) with a SearchDisplayController and a TableView
in .h:
#property (nonatomic, retain) IBOutlet UITableView *tableView;
I linked this in .xib file to the TableView: >
Then in cellforrow:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
if(listGoal){
Goal *goalz = nil;
if (tableView == self.searchDisplayController.searchResultsTableView)
{
goalz = [self.filteredListContent objectAtIndex:indexPath.row];
cell.textLabel.text = goalz.goalNaam;
}
else
{
goalz = [arr objectAtIndex:indexPath.row];
cell.textLabel.text = goalz.goalNaam;
cell.detailTextLabel.text = goalz.goalBeschrijving;
}
}
I test if I need the filteredListContent or the original array, arr. (Because I'm using a SearchDisplayController)
Which is working.
In another method,
if (tableView == self.searchDisplayController.searchResultsTableView)
is not working anymore, so I tried using
self.tableView
but this isn't working either and
(UITableView *)tableView
isn't working either.
I know something is wrong with my property declaration or linkages, but what is wrong ?
One way you can access search view in your custom method would be keep a strong reference to your search view when you get it. But I am NOT sure whether it would be valid across multiple searches.
May be you can just have a BOOL variable set and use that in your custom method. I think you would not be able to access search view in your custom method otherwise.
Related
I have a UITableView and it contains a custom UITableViewCell. To test, I have an array that has three strings in it. The UITableView delegate methods are called as expected, however, the tableView:cellForRowAtIndexPath delegate is always passed an NSIndexPath instance whose row property is always == nil:
tableView:cellForRowAtIndexPath is called 3 times (once for each object in my array). I added the tableView from within the designer (storyboard) and created an outlet for it. The UITableViewCell instances appear to be correctly instantiated which each call to this delegate. I just can't wrap my head around why the [indexPath row] value is always nil.
Interface(s):
In the implmentation file:
#interface FirstViewController ()
#property(nonatomic, strong)AppDelegate *sharedDelegate;
#property(nonatomic, strong)NSArray *userList;
#end
In the header:
#interface FirstViewController : UITableViewController <FacebookDelegate>
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#end
Init the custom cell:
-(void)viewDidLoad
{
[self.tableView registerClass: [ListCategoryCell class]forCellReuseIdentifier:#"ListCategoryCell"];
self.userList = #[#"d", #"g", #"f"]; // make some test data
}
And the delegate this is driving me mad:
//NSIndexPath.row is nil ?!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"ListCategoryCell";
ListCategoryCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = (ListCategoryCell *)[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
cell.titleLabel.text = [self.userList objectAtIndex:[indexPath row]];
cell.detailLabel.text = #"Detail";
return cell;
}
Am I missing something? Thanks!
Working Now
I left out some context (and I should not have) that I believe was very relevant to my problem. I created a UIViewController originally and then added a UITableView to this as the view. In the UITableView I created a custom prototype cell. I did all the house work:
UIViewController implemented the UITableViewDelegate & UITableViewDatasource.
Created and outlet for the UITableView.
Hooked up all the outlets
Everything seemed to work except for the fact that indextPath.row property was always nil. Some resources I found suggested that custom cells were not visible before the uitableview delegates were called.
In the end I made my class a subclass of UITableViewController. Things started working. I am still curious why my original attempt was failing.
Thanks for everyone's time. Some great comments helped me investigate some topics that are "good to know".
You need to provide at least two methods in view controller if you want it to manage your table view. They are:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
You've already provided the second, so your table view actually can produce cells but it doesn't know how many.The default value the first method returns is nil.That is the reason why you don't even have an index path.
Optionally:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
The default value is one,so you don't need to override this in case you have only one section
Make sure your view controller also follows delegate and datasource protocols.
I am trying to write an app with a 'main page' of UIButtons that when tapped will Segue to UITableView, which will in turn Segue to another View etc. I have no errors or warnings in my code, and I thought I designed it well, but when I run the app the PrototypeCells don't even appear.
This is how I have my Storyboard set up right now (I'm sorry but I can't post images yet, as I'm a new user). The little beer mug is a UIButton that successfully performs the Segue to the UITableView window (this is the one that doesn't load the PrototypeCells).
The Brew View Controller has no code in it other than the defaulted methods.
I created a class called Brewery and gave it the following properties
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *address;
#property (nonatomic, copy) NSString *info;
#property (nonatomic, copy) NSString *brews;
I created the Brewery View Controller and added the following methods along with the default code
- (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.breweries count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"BreweryCell"];
Brewery *brewObject = [self.breweries objectAtIndex:indexPath.row]; //might be an error in here
cell.textLabel.text = brewObject.name;
return cell;
}
Yet when I run this, the PrototypeCells aren't even showing. The ReuseIdentifier matches both in storyboard and in the code, and the View is attached to the dataSource and the Delegate. Can anyone help me figure out what I'm doing wrong? I am also new to site, so please tell me if there is something I am doing wrong or if you need more information to assist me.
Even though you have said you have set the dataSource, if numberOfSectionsInTableView is not being called then it means the data source is not set correctly.
I suggest checking this in viewDidAppear and logging the data source and delegate, and programatically checking the equal self.
There are a few pitfalls with setting IBOutlets in interface builder.
From what you have said in your blurb:
the View is attached to the dataSource and the Delegate
This is wrong. It should be the file's owner which is the View Controller.
Hello I am brand new to xCode and iPhone development. I have two different TableView controls on one page. I have NSArray #1 that needs to be the datasource of TableView #1 and NSArray #2 that needs to be the datasource for TableView #2.
The only trouble is that NSArray#1 populates both TableView1 and TableView2. I looked through the code and can't seem to find where you can distinguish which NSArray belongs to each TableView.
Any help will be appreciated. Thanks in advance!
#interface GrainBinContentsEstimatorViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource>
{
UITableView *tableViewGrainBinType;
UITableView *tableViewGrainType;
}
#property (strong, nonatomic) NSArray *arrayGrainBinTypes;
#property (strong, nonatomic) NSArray *arrayGrainTypes;
#property (nonatomic, retain) UITableView *tableViewGrainBinType;
#property (nonatomic, retain) UITableView *tableViewGrainType;
#implementation GrainBinContentsEstimatorViewController
#synthesize arrayGrainBinTypes, arrayGrainTypes, tableViewGrainBinType, tableViewGrainType;
- (void)viewDidLoad
{
[super viewDidLoad];
self.arrayGrainBinTypes = [[NSArray alloc]
initWithObjects:#"RF", #"RC45", #"RC60", nil];
self.arrayGrainTypes = [[NSArray alloc]
initWithObjects:#"Wheat", #"Corn", #"Soybeans", #"Rice", #"Milo", #"Barley", nil];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return #"Select Bin Type";
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.arrayGrainBinTypes count];
}
- (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 = [self.arrayGrainBinTypes objectAtIndex: [indexPath row]];
return cell;
}
In every delegate method (callback) the caller (tableview) is passed as a parameter. So you can switch based on this parameter like:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (tableView == self.tableViewGrainBinType) return [self.arrayGrainBinTypes count];
else return [self.arrayGrainTypes count];
}
You get the idea...
First of all, welcome to SO.
So, you have a reasonable design concept here: One array populates one table view. The data source/delegate of your table view is typically a UITableViewController or UIViewController, but it certainly doesn't have to be. In your case, it's your UIViewController. So, what happens is that when each table view loads, it asks its data source "Hey, how many rows/sections do I have? What do my cells look like?" and other questions.
In your case, you're not distinguishing between table views! So tableView1 is asking "what do my cells look like? Let's see what tableView:cellForRowAtIndexPath: has to say!" and you're giving it info from your arrayGrainByTypes array. Then tableView2 comes along and asks the same question, and uses the same method to get its answer. In each of these data source methods, you are typically given, as an argument to the method, which table view is asking for this information. So, just check which table view is asking!
if (tableView == self.tableViewGrainType) {
// table view 1's information is set here
else if (tableView == self.tableViewGrainBinType) {
// table view 2's information is set here
}
I'm stuck with a seemingly very simple app that I'm trying to develop
Basically, I have a UITable, and two buttons: red/blue
When a button is pressed, a row with corresponding title of that button is append to the table
I'm overwhelmed by how complicated UITableView has to be implemented (datasource, delegate, resuable identifier, etc)
Can anyone help me out with this, preferably show me detailed codes
For my Buttons, I have something like this
- (IBAction)buttonPressed:(UIButton *)sender{
NSString *item = sender.currentTitle;
[self.cellArray addObject:item];
[self.myTable reloadData];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.cellArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"The Table Cell";
self.myTableCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (self.myTableCell == nil) {
self.myTableCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
self.myTableCell.textLabel.text = [self.cellArray objectAtIndex:indexPath.row];
return self.myTableCell;
}
Since you are learning this..i will post a simple solution.
Make add a member variable NSMutableArray *cellArrays;
initialize it in your viewDidLoad
in buttonPressed check;
if([#"red" isEqualToString:[YourButton titleForState:UIControlStateNormal]])
{
[self.cellArrays addObject:#"red"];
}
else
{
[self.cellArrays addObject:#"blue"];
}
[self.YOURTABLEVIEW reloadData];
Now in your table view datasource method
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.cellArrays.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//in between your code;
YOURCELL.textlabel.text = [self.cellArrays objectAtIndex : indexpath.row];
}
Try this ..
I'd recommend subclassing UITableViewController, then override the dataSource and delegate methods and you should be good to go. Going straight to UITableView is more complicated without any obvious benefits.
You may not be using Core Data, but I still recommend this lecture because it hooks up a TableViewController and works great - all code included. Check it out:
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/node/289
The lectures in iTunes U explain everything further.
Enjoy,
Damien
I wanted to add that "One more thing, the compiler shows a warning says no reusable identifier. what exactly is that?" above...
His answer is correct, but to get rid of that compiler warning...
The tableviewcell of your tableview has to have an identifier. In IOS 5, in your storyboard, highlight the TableViewCell in your TableView, and enter a value in the Identifier. This must match the value in your code of the cell that you are creating.
I have a tableview with custom cells in my App and each cell contains two checkbox buttons.
The problem is, when a scrolling event is triggered (up or down) it's reloading the tableview. Therefore, the checkbox buttons become to initial state.
Please give me a solution.
Thanks you
You're going to have to maintain a list yourself to determine which cells should be checked or not. Remember that in tableView:cellForRowAtIndexPath:, a proper implementation will recycle cells so that you never have more than 10-15 cells instantiated. This can cause some funky results if you don't handle for it properly. When I've done a poor implementation, I've seen certain cell properties "carry over" from one cell to the next.
Anyway, here's what I'd recommend (based on what I think you're asking):
1. Create a class to back each UITableViewCell
2. Create a property in that class to determine which of the two checkboxes (or neither or both) should be checked.
3. In your ViewController/TableViewController, maintain an NSMutableArray/NSArray where 1 item in the array = 1 cell in the UITableView.
4. In your tableView:cellForRowAtIndexPath: method, get a reference to the appropriate item in your array.
5. Then, check that instance's properties and set the checkbox values appropriately.
Sample Code:
TableView.h
#interface TableView : UITableViewController
#property (strong, nonatomic) NSMutableArray *itemArray;
#end
TableView.m
#implementation TableView
#synthesize itemArray;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Assume you get a valid, custom UITableViewCell at this point (named "cell")
// Configure the cell...
NSObject *classItem = [[self itemArray] objectAtIndex:[indexPath row]];
[[cell checkBox1] setChecked:[classItem checkbox1Checked]];
[[cell checkBox2] setChecked:[classItem checkbox2Checked]];
return cell;
}
#end
You should set the state of the button in the datasource and load this state when creating the cell. I wrote a small Xcode project to demonstrate this.
Well you should not use the TableView as the datasource.
Every time the cell comes into view the UITableViewDataSource is asked for the UITableViewCell at as indexpath.
- (void) tableView:(UITableView *)tableView setImage:(UIImage *)image forCellAtIndexPath:(NSIndexPath *)indexPath
In the is method you should set the checkbox state as it is reflected in your dataSource.
When the checkbox is changed save it in the data source with the selected state.
Example:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"CheckedTableViewCell";
CheckedTableViewCell *cell = (CheckedTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
[[NSBundle mainBundle] loadNibNamed:cellIdentifier owner:self options:nil];
cell = (CheckedTableViewCell *)self.nibCell;
self.nibCell = nil;
}
item *item = [self objectAtIndexPath:indexPath];
cell.titleLabel.text = item.title;
cell.switch.on = item.selected;
return cell;
}
You could save the state in NSUserDefaults right when you click it. Just add a target with #selector(changedOne: ) and add the void statement:
- (void)changedOne: (id)sender {
NSUserDefaults *df = [NSUserDefaults standardUserDefaults];
NSString *row = [NSString initWithFormat:#"toggleOneRow%i",indexPath.row];
if (sender.on) {
[df setBool:YES forKey:row];
}
else {
[df setBool:NO forKey:row];
}
}
Are you using cellForRowAtIndexPath. If yes, then instead of
static NSString CellIdentifier=#"CellIdentifier"
use
NSString *CellIdentifier=[NSString stringWithFormat=#"CellIdentifier%d",indexPath.row];
Other approach you can take is assign tags to checkboxbuttons and take one dictionary in appDelegate file and set value for checkbox tag.initially you may set is either checked or unchecked.and set the values in cellforrowatindexpath method. set the values of checkboxes as per appdelegate dictionary.and update the state in appdelegate dictionary when user selects or deselects the button.