first off I'm new to iOS development so this may be a simple issue,
I've got the following code
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
cell.textLabel.text = #"Hello!";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
NSLog(#"Creating cell for %i:%i", indexPath.section, indexPath.row );
return cell;
}
Now the table shows, but all the rows are blank. And the cells are being created. Not sure if it matters but im not using xib's or story boards so i dont know if its a styling issue.
I'm really in the dark here about what im doing. I've tried to follow a few tutorials and every time i end up at the same place with a blank table.
Thank you for all help! I'm open to ideas and possible tutorials etc.
(This is more of a comment, but it's too big for the comment field.)
I've copied your methods exactly into my .m file, and it works. The rest of the file looks like this:
#interface MYViewController ()
#end
#implementation MYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 640) style:UITableViewStylePlain];
[table setDataSource:self];
[table setDelegate:self];
[self.view addSubview:table];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
I'm assuming you set the data source, since you're getting the NSLogs to print.
Are you sure that the UITableView is not hidden, does not have a 0 alpha, and is above all other views?
If the data you display has the possibility of changing when you go out and back into the view, I'd advice use of
[self.yourTableViewObject reloadData];
This will call all the delegate methods (getting the sections, individual cells) and repopulate your table view.
Related
I am new in ios dev, so my question might be so easy!
I want to use a UITableViewController in different places (reusable), so as a .net developer I think to create one UITableViewController and load it in different views (like Partial views in MVC.net)
I know the UIView that wants to contain this table should implement UITableViewDelegate and UITableViewDataSource methods, but I don't want to do that, I mean I want the Partial view to handle all of those logics because that is the view that has the access to CoreData.
I already searched for different solutions and in almost all of them I have to implement those methods in every single view that wants to use that partial view.
any suggestion?
Thanks
Yes, you can handle the logic in the partial view for example your exTableviewController.
Handle protocol UITableViewDataSource & UITableViewDelegate in your exTableViewController as below.
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Test"];
if (cell==nil) {
cell= [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Test"];
// cell.textLabel.textAlignment = NSTextAlignmentCenter;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.textLabel.text = [NSString stringWithFormat:#"%i", indexPath.row];
return cell;
}
And associate the partial view and your view controller as below.
#interface YourViewController ()
#property (nonatomic, strong) exTableViewController *tableVC ;
#end
#implementation YourViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableVC = [[exTableViewController alloc] init];
[self.view addSubview:_tableVC.view];
// Do any additional setup after loading the view, typically from a nib.
}
#end
You can also customize the subview's size by using YourViewController.xib.
And binding self.tableVC with the subview in xib file.
Hope this can help you.
I have UITableView...when user tap on row, another screen is opened. The problem is, that sometimes, I tap once, but didSelectRowAtIndexPath calls several times. How to prevent that ?
The one case how to reproduce that situation is (you even can try to reproduce that on native iPhone settings):
Tap one row but do not release finger
SLIDE few next rows from left to right or from right to left (not just tap, you should slide) next few rows in different order by other hand
Release finger
You will see that blue selection is on several rows, and what screen will be opened is random
UPDATE:
In didSelectRow I just started new controller, where in viewDidLoad synchronization begin.
And if to reproduce my scenario step by step, than synch can be started several times
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
SecondViewController *secondViewController =
[SecondViewController alloc] init];
[self.navigationController
pushViewController:secondViewController animated:YES];
[secondViewController release];
}
Yes, I find the same situation.
Tap one row but do not release finger.
Keep pressing and moving the finger slightly until the row deselected.
Keep the first finger pressing, and tap the screen some times by another finger.
Release all fingers.
Then you can see didSelectRowAtIndexPath method called several times.
I created a new project for test it, and just used the following code. It was reproduced in every times.
So I think it is a bug of iOS SDK !
#import "SPViewController.h"
#interface SPViewController ()
#property (nonatomic, strong) UITableView *tableView;
#end
#implementation SPViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 30;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"cellIdentifier";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [NSString stringWithFormat:#"Test Cell %d", indexPath.row];
return cell;
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 66;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"%s %#", __FUNCTION__, indexPath);
}
#end
In my Map application I have segment controller on main screen and using that I have Map View & tableview(both are UIView). I have tried everything but my data is not loading in my tableview. Here is my tableview code. Here marker is attribute in my xml file which contain Showroom name and Iam able to parse this.
.h file
#interface HViewController : UIViewController<UITableViewDataSource, UITableViewDelegate> {
UITableView *_tableView;
}
#property (nonatomic, retain) IBOutlet UITableView *_tableView;
#end
.m file
Edited = with ViewWillAppear,viewDieLoad, segement action method
#synthesize tableView;
- (void)viewDidLoad {
appDelegate = (HAppDelegate *)[[UIApplication sharedApplication] delegate];
[segmentedControl addTarget:self action:#selector(segmentAction:)
forControlEvents:UIControlEventValueChanged];
}
- (void)viewWillAppear:(BOOL)animated
{
self._tableView.rowHeight = 80.0;
[_tableView reloadData];
}
-(void)segmentAction:(id)sender;{
UISegmentedControl* segCtl = sender ;
if( [segCtl selectedSegmentIndex] == 0 )
{
NSLog(#"segmentAction mapView");
mapView.hidden = NO;
_tableView.hidden = YES;
//[ self.view addSubview:mapView] ; // adding view to segmentindex 0
}
if( [segCtl selectedSegmentIndex] == 1 )
{
NSLog(#"segmentAction _tableview");
_tableView.hidden = NO;
mapView.hidden = YES;
//[ self.view addSubview:_tableview] ;
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"appDelegate.markers _tableview");
return [appDelegate.markers count];
}
//method to print row(showroom count on Header)
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection: (NSInteger)section {
if(section == 0)
return [NSString stringWithFormat:NSLocalizedString(#"ShowRooms[%d]", #"Showroom format"), [appDelegate.markers count]];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
static NSUInteger const kShowroomNameLabelTag = 2;
UILabel *ShowroomNameLabel = nil;
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
ShowroomNameLabel = [[[UILabel alloc] initWithFrame:CGRectMake(50, 1, 300, 20)] autorelease];
ShowroomNameLabel.tag = kShowroomNameLabelTag;
ShowroomNameLabel.font = [UIFont boldSystemFontOfSize:18];
[cell.contentView addSubview:ShowroomNameLabel];
NSLog(#"UITableViewCell.markers _tableview");
}
else
{
ShowroomNameLabel = (UILabel *)[cell.contentView viewWithTag:kShowroomNameLabelTag];
}
marker *aMarker = [appDelegate.markers objectAtIndex:indexPath.row];
//ShowroomNameLabel.text = aMarker.name;
ShowroomNameLabel.text= [NSString stringWithFormat:#"ShowroomName= %#", aMarker.name];
return cell;
}
In my tableview Header it shows data count correctly but not showing data.
I have connected delegate,datasource,_tableview to fileOwner of the HViewController in which I have put above code. Plz suggest something where I am wrong. I am parsing XML file and getting data in console alos I can show it on Map. But I am not able to load data in my tableview.
Try moving [_tableView reloadData] to viewWillAppear.
UITableViewController reloads the table view's data in viewWillAppear, not viewDidLoad. I can't tell you the exact reason for which this would make a difference, though I can think of several. Anyway, it's worth a try.
EDIT:
RESPONSE TO COMMENTS
If titleForHeaderInSection: is being called, then there is a data source connected to a table view. So, the problem is not a lack of a data source connection.
I am guessing you have 2 table views in your .xib file: a large one & a short one below it. The large table view is not connected to the data source, so it just displays blank lines. The short table view is connected to the data source. But, it is just tall enough for a header and has no space left to display any cells. Thus, titleForHeaderInSection: is called, but cellForRowAtIndexPath: is not because there is no space to display any cells.
Note that this is just a guess, but it is the only scenario I can think of that would cause the behavior you described. The code you posted looks ok, although a bit more complicated than necessary.
There is no question that reloadData should be in viewWillAppear. That's where the Apple engineers put it when they created the UITableViewController class. So, to put it elsewhere, you have to believe you know better than they do.
Just came across some very strange behavior in my app. I've recreated the problem in a simplest-case scenario:
NSMutableArray *data;
- (void)viewDidLoad {
[super viewDidLoad];
data = [[NSMutableArray arrayWithObjects:#"1", #"2", #"3", nil] retain];
}
- (UIView *)tableView:(UITableView *)aTableView viewForHeaderInSection:(NSInteger)section {
UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, 32.0)];
header.backgroundColor = [UIColor lightGrayColor];
[header addSubview:self.button];
return header;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[data removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return data.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
cell.textLabel.text = [data objectAtIndex:indexPath.row];
return cell;
}
- (void)dealloc {
[super dealloc];
}
Every time I delete a row; the button in my header disappears! This happens no matter what type of rowAnimation I use. If I scroll the table up so that the header scrolls off; the button returns when the header returns. The button is created in the xib file.
I can work around it in one of 2 ways:
Reloading the tableView data after the delete; with a delay so that the deletion animation completes first.
Creating the button in viewForHeaderInSection instead of in the interfaceBuilder.
I'd really like to understand what's going on here. Where is the button going? I've confirmed that viewForHeaderInSection is called when I delete a row.
Edit I tried changing it so that the button is created in viewForHeader, instead of in the xib, but it's causing other strange issues... when I create or delete the button, I am setting certain properties such as the title and enabled depending on how many items there are in the table. When I delete the last row in the table, I don't see the update in text and enabled status until I scroll the button off the screen and back on again.
Because you only have one instance of your button, if the table view decides to create a new header view then the button will be removed from its current parent and moved to the new one. Even if you only have one section in your table, the table view may be doing some strange things internally and recreating header views off-screen so you can't rely on just one being in existence at any one time.
You should create the button in viewForHeaderInSection: and work around your other problems. Rather than only updating the button properties in viewForHeaderInSection you should handle any delete events so that deleting a row will also update the button.
Where is your implementation of the delegate method tableView:heightForHeaderInSection: ? That is necessary for tableView:viewForHeaderInSection: to work correctly. Check the docs.
Reference for UITableView delegate
I've confirmed that
viewForHeaderInSection is called when
I delete a row.
Have you confirmed that viewForHeaderInSection is called for the particular header with the added button?
Then, try adding
[header bringSubviewToFront:self.button];
after adding the button.
Well I at least managed to get around my issue... I made an iVar and property for the view that I create in viewForheaderAtSection, and then I only create a new view if I don't have one already. Otherwise I just return the header I already had; something like this:
- (UIView *)tableView:(UITableView *)aTableView viewForHeaderInSection:(NSInteger)section {
if (!self.myHeader){
UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, 32.0)];
header.backgroundColor = [UIColor lightGrayColor];
[header addSubview:self.button];
self.myHeader = header;
[header release];
}
return self.myHeader;
}
This works, but it would still be great to understand what exactly is going on. As far as I can tell, viewForHeaderInSection is being called by the system, but then the instance of the view that I return in that method is not actually being used / shown; at least not until I do something that causes the view to redraw...
So i have this very basic ipad view controller and i was doing some testing with multiple UITableViews in the same view. The issue I was having was when I selected a row, it would throw a EXC_BAD_ACCESS so I turned on the stack logging and found this
*** -[VCTables tableView:didSelectRowAtIndexPath:]: message sent to deallocated instance 0x4c0ad40
Then i started looking at my code and could not figure out for the life of me what is causing it. I have UITableViewDataSource and UITableViewDelegate on my view controller and have all the appropriate code to handle did select row at index. It draws the tables properly, it just doesnt seem to be hitting self as the datasource.
I have tried building the UITableViews in code, and also in Interface builder. I have re-downloaded and installed XCode 3.2.3 SDK 4.0.2 after uninstalling it and restarting. I couldn't for the life of me see what I am missing but after doing the previous, I am convinced now (i guess) that it is a code issue rather than the IDE, I just cant open my eyes wide enough to see the code issue.
Also, this happens with just one table as well. And with 2 tables, it happens no matter which table I select
here is some code:
VCTables.h
#import <UIKit/UIKit.h>
#interface VCTables : UIViewController<UITableViewDelegate,UITableViewDataSource> {
UITableView *table1;
UITableView *table2;
}
#end
VCTables.m
#import "VCTables.h"
#implementation VCTables
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 50;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 7;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = [[NSString alloc] initWithString:#"yourCell"];
if(tableView.tag == 2000){
[CellIdentifier release];
CellIdentifier = [[NSString alloc] initWithString:#"myCell"];
}
UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if(tableView.tag == 2000){
[cell.textLabel setText:[NSString stringWithFormat:#"%d",indexPath.row]];
}else{
[cell.textLabel setText:[NSString stringWithFormat:#"%d%d",indexPath.row,indexPath.section]];
}
[CellIdentifier release];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
NSLog(#"selected");
}
- (void)viewDidLoad {
[super viewDidLoad];
table1 = [[UITableView alloc] initWithFrame:CGRectMake(20, 73, 320, 480) style:UITableViewStylePlain];
table1.delegate=self;
table1.dataSource=self;
table1.tag=2000;
[self.view addSubview:table1];
table2 = [[UITableView alloc] initWithFrame:CGRectMake(483, 73, 320, 480) style:UITableViewStylePlain];
table2.delegate=self;
table2.dataSource=self;
table2.tag=2000;
[self.view addSubview:table2];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)dealloc {
[super dealloc];
}
#end
I'm not sure it gets more basic than that. Please tell me the rookie mistake that is so painfully obvious that I must stop posting here. Thanks in advance
message sent to deallocated instance 0x4c0ad40
This error indicates that your VCTables instance has been released. The UITableView still has a reference to it (the delegate property), so it is trying to send a message to a released object. The common term for this is a zombie.
In order to debug, you should look at how the memory management is being done for your VCTables object. Where is it created, and who owns it?
If you can make use of Apple's performance tools, try using the zombies tool to find out where that VCTables object is released.