I am trying to embed a UITableView in my View Controller (not a TableViewController).
I am unable to get any of my data to show.
Here is the relevant code:
M file:
#interface ViewController () <CBCentralManagerDelegate, CBPeripheralDelegate, UITableViewDelegate, UITableViewDataSource>
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) NSMutableArray *Device_array_name;
#end
.
.
.
- (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.Device_array_name[indexPath.row];
return cell;
}
I've also defined number of sections and rows, and my array does indeed have content. I'm pretty new to iOS development so I've no doubt missed something.
Thanks
Delegates & Datasources should be defined for UI Controls to get called their respective delegates.
For Instance : In your viewDidLoad function define
tableView.delegate = self
tableView.datasource = self
It will work.
Set the array allocation in your view did load.
Device_array_name=[NSMutableArray alloc]init];
Set the tableview delegates in viewdidLoad
tableview.delegate=self;
tableview.datasource=self;
After give the count of an array in Number of rows in section
return Device_array_name.count;
In your cellForRow AtIndexpath method
cell.textLabel.text=[self.Device_array_name objectAtIndex:indexPath.row];
There could be 4 reason (most probably)
1> You delegate and datasource are not set
tableView.delegate = self
tableView.datasource = self
2> Your datasource array is nil (Device_array_name)
3> Your IBOutlet is not connected with tableview
4> Your tableview frame is becoming zero due to autloayout or something else (check console at runtime)
I think you just need to initialize the delegate and dataSource for your tableView property to your ViewController.
If you embed this way, you don't have default setting for the UITableView like you have when you use UITableViewController directly. You will need to set it up by yourself. Most likely, it's because you have not wired up your delegation object. Second will be, your UITableView is invisible. That also causes the problem because the delegate methods will not be called.
i think go to storyborad and set delegate,datasource in there.if you using by storyborad.i hope will work.
Here is my list of the possible problems:
The #IBOutlet for the table view is not connected in Interface Builder. Solution: check connection in Interface Builder.
The outlet is set, but the view controller placed in the storyboard is not of your custom UIViewController subclass, but the default UIViewController. In this case, none of your code will be executed. Solution: specify the view controller's class is the identity inspector (center tab).
The dataSource property of the table view is not set to your view controller. Solution: Assign it in either Interface Builder (storyboard) or programmatically inside viewDidLoad() or later.
You are not implementing the UITableviewDataSource protocol method:
tableView(_:numberOfRowsInSection:) (i.e., the table view "thinks" it has 0 rows to display). In this case, tableView(_:cellForRowAtIndexPath:) will not be called (you can confirm this by placing a break point). Solution: Implement the method and return the count property of your model object array.
The array that serves as the data source for your table view is empty (has zero elements). Solution: Make sure the array contains your model objects.
I might have left some other common mistake out... Let me know.
Addendum: Unless you have a compelling reason not to, I would strongly suggest that you use a stock UITableViewController instead of manually adding a UITableView to a plain UIViewController. You get a lot of functionality and setup for free.
Related
I have been using objective c for a few months now, using different foundation classes and generally playing around with the language.
In my own experience nothing has been more confusing than UITableView; Below is a bit of code that does not do much.
//the header file
#interface SLDataBankListTableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource>
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#end
//implementation
#interface SLDataBankListTableViewController ()
#property (strong, nonatomic) SLDataSourceObject* dataSource;
#end
#implementation SLDataBankListTableViewController
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
_dataSource = [[SLDataSourceObject alloc] init];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _dataSource.dataBankNames.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"reuse"];
cell.textLabel.text = [_dataSource.dataBankNames objectAtIndex:indexPath.row];
return cell;
}
#end
I have successfully used this class for over a dozen times and every time I make some stupid mistake like now. Finally I gathered some courage and decided to ask for help.
What are the subtle things, nuances of this class that I don't seem to grasp?
Edit: this is a part of a small program, other parts of it work fine, but the table displays nothing; Some changes have been recommended that are important but did not solve the problem.
It is a little hard to debug without known what is not working, but I see some things which might help you out.
UITableViewController has its own tableview but you seem to have another tableview wired up in a nib. Either use the UITableViewController tableview, or create your own, don't do both.
in cellForRowAtIndexPath you are creating a new cell every time instead of reusing the cells you have.
The delegate methods for the tableview can be called before viewWillAppear. You should create your datasource object earlier. I suggest viewDidLoad:. (Another reason viewWillAppear is a bad choice is that it can be call multiple times, and you can end up creating and destroying many datasource objects for no reason)
Hope that helps.
The big thing to remember about a table view is that it's a way for user to interact with an array of objects. The array is represented by a datasource, and the datasource methods describe what the view needs to know:
how many objects are in the array (called numberOfRowsInSection:)
how to display each one of the objects (called cellForRowAtIndexPath:)
To answer the latter question, the datasource must answer a view. That view's job -- like any view -- is to represent an object for the user. In row the table view uses a UITableViewCell.
The datasource array can be arbitrarily large, so directly mapping UITableViewCells to its elements can get arbitrarily expensive in memory terms. Rather than create a cell for every object in the array, the table view reuses cells.
When a cell scrolls off the top, the "new" one that appears at the bottom isn't new, it's the old cell handed back to the datasource to be reconfigured for the new row. To accomplish this, your datasource is expected to not allocate a new cell, as #JonRose correctly points out, but to ask the table view for a reused cell using dequeueReusableCellWithIdentifier.
I won't go into the WHY on this one, I'll just explain what I need.
I have a property in my implementatioon file like so...
#property (nonatomic, strong) MyCustomCell *customCell;
I need to initialize this on viewDidLoad. I return it as a row in cellForRowAtIndexPath always for the same indexPath, by returning "self.customCell".
However it doesn't work, I don't appear to be allocating and initializing the custom cell correctly in viewDidLoad. How can I do this? If you know the answer, save yourself time and don't read any further.
Ok, I'll put the why here in case people are curious.
I had a table view which was 2 sections. The first section would always show 1 row (Call it A). The second section always shows 3 rows (Call them X, Y, Z).
If you tap on row A (which is S0R0[Section 0 Row]), a new cell would appear in S0R1. A cell with a UIPickerView. The user could pick data from the UIPickerView and this would update the chosen value in cell A.
Cell X, Y & Z all worked the same way. Each could be tapped, and they would open up another cell underneath with their own respective UIPickerView.
The way I WAS doing this, was all these cell's were created in the Storyboard in the TableView, and then dragged out of the View. IBOutlets were created for all. Then in cellForRAIP, I would just returned self.myCustomCellA, or self.myCustomCellY.
Now, this worked great, but I need something more custom than this. I need to use a custom cell, and not just a UITableViewCell. So instead of using IBOutlets for all the cells (8 cells, 4 (A,X,Y,Z) and their 4 hidden/toggle-able UIPickerView Cell's), I created #properties for them in my implementation file. But it's not working like it did before with the standard UITableViewCell.
I'm not sure I'm initializing them correctly? How can I properly initialize them in/off viewDidLoad so I can use them?
.m
#interface MyViewController ()
#property (strong, nonatomic) MyCustomCell *myCustomCellA;
...
viewDidLoad
...
self.myCustomCellA = [[MyCustomCell alloc] init];
...
cellForRowAtIndexPath
...
return self.myCustomCellA;
...
If only I understood your question correctly, you have 3 options:
I would try really hard to implement table view data source with regular dynamic cells lifecycle in code and not statically – this approach usually pays off when you inevitably want to modify your business logic.
If you are certain static table view is enough, you can mix this method with overriding data source / delegate methods in your subclass of table view controller to add minor customisation (e.g. hiding certain cell when needed)
Alternatively, you can create cells using designated initialiser initWithStyle:reuseIdentifier: to instantiate them outside of table view life cycle and implement completely custom logic. There is nothing particular that you should do in viewDidLoad, that you wouldn't do elsewhere.
If you have a particular problem with your code, please post a snippet so community can help you
I suggest you to declare all your cells in storyboard (with date picker at right position) as static table and then override tableView:heightForRowAtIndexPath:
Define BOOL for determine picker visibility and its position in table
#define DATE_PICKER_INDEXPATH [NSIndexPath indexPathForRow:1 inSection:0]
#interface YourViewController ()
#property (assign, nonatomic) BOOL isPickerVisible;
#end
Then setup initial value
- (void)viewDidLoad {
[super viewDidLoad];
self.isPickerVisible = YES;
}
Override tableView delegate method
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath isEqual:DATE_PICKER_INDEXPATH] && !self.isPickerVisible) {
return 0;
} else {
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
And finally create method for toggling picker
- (void)togglePicker:(id)sender {
self.isPickerVisible = !self.isPickerVisible;
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
which you can call in tableView:didSelectRowAtIndexPath:
According to your problem, you can create pairs (NSDictionary) of index path and bool if its visible and show/hide them according to that.
Here's what I was looking for:
MyCustomCell *cell = (MyCustomCell *)[[[UINib nibWithNibName:#"MyNibName" bundle:nil] instantiateWithOwner:self options:nil] firstObject];
I have declared an array in ViewController and displaying it in table view. I am passing values for an array from EditViewController. But the values are not displaying in table view. I am using following code.
ViewController.h
#property (nonatomic, strong) NSMutableArray *tableData;
ViewController.m
ViewDidLoad:
tableData = [NSMutableArray arrayWithObjects:#"",nil];
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
EditViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
ViewController *vc;
vc = [segue destinationViewController];
NSString *str = [NSString stringWithFormat:#"%ld", selectedRow];
[vc.tableData addObject:str];
}
Please advice.
Connect the delegate and datasource to self in the viewDidLOad of editViewController
tableView.delegete=self;
tableView.Datasource=self;
If there is no data in the tableview itself, hit a breakpoint at
cellForRowAtIndexPath,
and Still if it dsnt hits the breakpoint,connect the Delegate and Data source for the tableview with the View Controller.
[EDIT]
If it is still not called, go to storyboard, check if the bounds of the tableview, is more than that of the vc, that means, check if the tableview is inside the view controller and no part of the tableview is crossing the bounds of the view controller.
Plz make sure you have
-tableView:numberOfRowsInSection:
method defined. This method should return value greater than 0 so that
-tableView:cellForRowAtIndexPath:
gets called.
you are add string to nsarray object which is not allocated.
you have to create nssarray with string and pass to the vc.tableData.
There may be a few problems with this.
First, it's best to set a the NSMutableArray property "tableData" to an existing array passed in during the segue. Right now you're adding a single string to a mutable array which, unless you wrote a custom initializer for the ViewController in which you alloc-init'ed the NSMutableArray, it can't exist until ViewDidLoad which is after the segue is performed, so you're passing the string to black abyss of "nil".
It's best to use base types as receiving properties in prepareForSegue, and then in your case to pass the ViewController's array an already existing array from the EditViewController.
Also, you may not be telling the view controller how many cells to actually create. Make sure numberOfSectionsInTableView returns a value (in this case just 1), and that numberOfRowsInSection returns "[self.tableData count]".
And if you didn't create ViewController as inheriting from UITableViewController, you'll need to set that, and connect the delegate and datasource manually in the storyboard like Light Yagami pointed out. Though it would probably be easier to just create a new custom class file that inherits from UITableViewController because it will give you some good boilerplate code.
And also make sure that in your storyboard, your TableViewController's class is set to your custom class file.
I hope you did not pass numberOfSectionsInTableView as 0. Please check that once. It must be 1 or more based on requirement. And same for numberOfRowsInSection.
Remove this line from your ViewDidLoad Method
tableData = [NSMutableArray arrayWithObjects:#"",nil];
I am new to iOS i am working on uitableview cell i had drag and drop the button to table view cell from objects inspector. but when i am making its IBoutlet it is showing an error like "Outlets cannot be connected to repeating content" what does it means?? we cant make outlets of UIbutton in tableview cell.kindly review it . i am stuck in it.i am making an outlet like this:
#property (weak, nonatomic) IBOutlet UIButton *sa;
and the error is "The sa outlet to the UIbutton is invalid"
Your answer is that you use an object in UITableViewCell by reusing it,
So you can't create it's outlet except you create Your class for your "UITableViewCell".
Below is a reference for you,
I hope that it's useful for you.
You need to drag and drop the object in your UITableViewCell,
Then you have to give tag for that object.
then you can use it with its tag.
First give an identifier to UITableViewCell,
Below is a reference image for it.
Then give a tag to your UI object,
As this in this reference image.
Below is sample code for you which I use regularly,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *Cell = [self.TableListRegion dequeueReusableCellWithIdentifier:#"List"];
UIButton *objectOfButton = (UIButton *)[CellLast viewWithTag:200];
[objectOfButton addTarget:self action:#selector(YourSelector:) forControlEvents:UIControlEventTouchUpInside];
return Cell;
}
Now you can receive that button event by,
-(IBACTION)YourSelector:(id)sender{
// Your Button in Cell is selected.
// Do your stuff.
}
Feel free to ask if you need more help regarding it.
You can create subclass for UITableViewCell like below code
Create new class named CCell.h and CCell.m
in CCell.h
#interface CCell : UITableViewCell
#property(nonatomic,strong)IBOutlet UILabel *lblTemp;
#property(nonatomic,strong)IBOutlet UIButton *btnTemp;
#end
Now in your Viewcontroller.h
#import "CCell.h"
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CCell *cell = (CCell *)[tblView dequeueReusableCellWithIdentifier:#"CCell"];
cell.lblTemp.text = #"asd";
cell.btnTemp.tag = indexPath.row;
[cell.btnTemp addTarget:self action:#selector(btnTempClicked:) forControlEvents:UIControlEventTouchUpInside]
return cell;
}
-(void)btnTempClicked:(UIButton *)btnTemp
{
NSLog(#"Button Clicked Index = %d",btnTemp.tag);
}
Now open your Xib > tap on your UITableviewCell > open right side navigator > open 3rd tab named (Custom Class) > add Class = CCell > now open last tab you will get lblTemp bind option.
Maybe this will help you.
Since you are creating a custom cell, you need to create a class for it. You will subclass UITableViewCell.
For example (using the property that you had in your question):
Create a new Objective-C Class. Set the subclass to: UITableViewCell
Give it an appropriate name (i.e. cell)
In your cell.h file:
Create your property: #property (weak, nonatomic) IBOutlet UIButton *sa;
In the cell.m file:
#synthesize sa = _sa;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
3.In Interface Builder, go back to the row that you created.
Click the "Show Identity Inspector".
Under "Custom Class", set that to your cell file.
4.Hold down the "Option" key and click the "cell.h" file. Then connect the button to the IBOutlet.
5.In your table view controller file:
import your cell.h file.
In cellForRowAtIndexPath method:
Cell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
That's it!
Everything should work then. Hope this helps!
You can't, because the button is part of a cell, and there will (possibly) be multiple instances of that cell when the app runs.
Assume that you can make the connection, and there are 2 cells (and thus 2 buttons) when the app runs, Cocoa Touch can't decide which button will be referenced by that only outlet (neither can you).
You can subclass the UITableViewCell, ask the table view to use your subclass for its cells, and connect the button to the outlet in the subclass. In that case there will be multiple instances of the subclass, and each instance will map to one cell.
Whenever you need want to create custom tableView cell it is recommended to subclass UITableViewcell and add UIButton in that class. And in your tableview delegate method cellForRowAtIndexPath you can create an object of subclassed tableviewCell for every cell.
I have done in UITableviewcell cell's label's outlet connection in UIViewController,it should changed to Create a CustomCell in Subclass of UITableviewcell,then done in outlet connection in this subclass that error cleared.
#Mishal Awan
If you really want to do that and your have a finite number of cells. U can :
Changing your ViewController to be a subclass of UITableViewController, then drage a Table View Controller file to your StoryBoard
Changing the content of Table View in your StoryBoard from Dynamic Prototypes to Static Cells
Then you can add some views to your cell, for example some labels
Connectting the label to your ViewController and continue the remaining work
If you want to create a reusable cell, forget what i have said above
A very simple solution is:
Just take the view or NSLayoutConstraint reference outlets in the subclass of table view cell instead of table view controller and access using object of table view cell in cellForRowAtIndexPath method or any other method.
Note: This is a repetitive object so you can't take reference in table view controller.
I try to display objects of an array in a tableview.
This is a single screen app, I'm using storyboard.
When running - the tableview appears as an empty grid. the data of the objects is not displayed. what may cause this?
Having 2 required methods numberOfRowsInSection and cellForRowAtIndexPath I suspect the last one.
The .h file contains this row:
#interface MYViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
I set the delegate & datasource via the code as you suggested. still empty grid.
This is my implementation:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [listRecipes.recipeArray count]; }
-(UITableViewCell )tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString cellIdentifier = #"ListCellIdentifier"; MYCustomListCell* listCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; NSString* dataString = listRecipes.recipeArray[indexPath.row]; listCell.listName.text = dataString; listCell.imageView.image = [UIImage imageNamed:dataString]; return listCell; }
I try to display data from an array in MVC .
If the array is local - the data is displayed
Can you please advise what to do?
Thank you in advanced.
Always remember to hook up your table's delegate and datasources.
Being a UIElement on a UIViewController that conforms to these two protocols is not enough for Xcode to assume that that UIViewController should be the delegate and/or datasource for the table.
Right click on your tableview, drag from delegate & datasource to your UIViewController.
You can also set these programmatically via:
self.table.datasource = self;
self.table.delegate = self;
And if you're still having trouble after this, you'll have to show us how you're implementing the datasource protocol methods.
Check if your initialisation of tableview delegate and datasource would be before the recipeArray is initialised. In this case you will have to tableView.reload() after the items are added to recipeArray .