Unrecognized selector sent to instance when adding a UITableView as SubView - ios

When i've created a UITableView in the code en add it as a subview in the code it is all working fine. There is green tableview visible.
Example of the code i've created for that.
- (void)getOverviewTable
{
// Adding the TableView
OverviewTableViewController *overviewTableViewController = [[OverviewTableViewController alloc] init];
UITableView *overviewTableView = [[UITableView alloc] initWithFrame:(CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height))];
// Set the datasource and delegete will come here
[overviewTableView setBackgroundColor:[UIColor greenColor]];
[self.view addSubview:overviewTableView];
}
But after i've set the DataSource and the Delegete for the TableView i will receive a warning.
The code in total for reaching it is as follows:
- (void)getOverviewTable
{
// Adding the TableView
OverviewTableViewController *overviewTableViewController = [[OverviewTableViewController alloc] init];
UITableView *overviewTableView = [[UITableView alloc] initWithFrame:(CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height))];
// Set the datasource and delegete will come here
[overviewTableView setDataSource:overviewTableViewController];
[overviewTableView setDelegate:overviewTableViewController];
[overviewTableView setBackgroundColor:[UIColor greenColor]];
[self.view addSubview:overviewTableView];
}
The most of the time it is just an EXC_BAD_ACCESS error, but sometimes it shows me the following error.
[UITransitionView numberOfRowsInSection:]: unrecognized selector sent to instance
The 'OverViewTableViewController' is replaced by just an empty UITableViewController class but the error is still showing up.
(Point of the application is an fullscreen takeover which has to be swiped away to see the tableview underneath it)
Edit:
The function is called from the viewDidLoad function
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"bg.jpg"]]];
// Setting the home takeover
[self setHomeTakeOver];
// Wait one seconde before we load the tableview
[self getOverviewTable];
//[self performSelector:#selector(getOverviewTable) withObject:nil afterDelay:1.0];
}

What I think is you have your project ARC enabled and from your code segment what i understand is that overviewTableViewController is released through ARC as soon as it leaves the scope of the function getOverviewTable. So, better declare the overviewTableViewController in .h file(#property (nonatomic, strong) OverviewTableViewController *overviewTableViewController; ).
If you do this then the code will look like this
in .h file
#property (nonatomic, strong) OverviewTableViewController *overviewTableViewController;
//// I have strong reference rather than assign
in .m file
- (void)getOverviewTable
{
// Adding the TableView
overviewTableViewController = [[OverviewTableViewController alloc] init]; //// I have made overviewTableViewController as member variable.
UITableView *overviewTableView = [[UITableView alloc] initWithFrame:(CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height))];
// Set the datasource and delegete will come here
[overviewTableView setDataSource:overviewTableViewController];
[overviewTableView setDelegate:overviewTableViewController];
[overviewTableView setBackgroundColor:[UIColor greenColor]];
[self.view addSubview:overviewTableView];
[overviewTableView reloadData];
}
Also be sure that OverviewTableViewController has implemented the datasource methods like
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

Try this.
[overviewTableView setDataSource:self];
[overviewTableView setDelegate:self];
Also confirm to tableviewDelegate and datasource and implement following methods.
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 10;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier=#"CellIdentifier";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
return cell;
}

You might have forgotten to implement this method.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
}

Try setting the table view controller's tableView property to overviewTableView. I don't know off hand if the UITableViewController must have that property set.
- (void)getOverviewTable
{
// Adding the TableView
OverviewTableViewController *overviewTableViewController = [[OverviewTableViewController alloc] init];
UITableView *overviewTableView = [[UITableView alloc] initWithFrame:(CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height))];
// Set the datasource and delegete will come here
[overviewTableView setDataSource:overviewTableViewController];
[overviewTableView setDelegate:overviewTableViewController];
//THIS IS THE NEW LINE
//a UITableViewController needs to know UITableView that it's managing
[overviewTableViewController setTableView:overviewTableView];
[overviewTableView setBackgroundColor:[UIColor greenColor]];
[self.view addSubview:overviewTableView];
}

Related

Tableview is not visible on UIViewController

UITableView is not visible on the UIViewController Class.
On Storyboard added a new UIViewController set to related SlideViewcontroller class to it, Add a new UITableView (tbl_Slide), set the datasource and delegate to UIViewController in storyboard for the added UITableView.
And also included the related datasource and delegate methods to the UIViewController class.
- (void)viewDidLoad {
[super viewDidLoad];
self.tbl_SlideMenu = [[UITableView alloc]
initWithFrame:CGRectMake(0, 80, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStylePlain];
self.tbl_SlideMenu.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
self.tbl_SlideMenu.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.tbl_SlideMenu.separatorColor = [UIColor lightGrayColor];
self.tbl_SlideMenu.dataSource=self;
self.tbl_SlideMenu.delegate=self;
[self.view addSubview:self.tbl_SlideMenu];
}
Since added the UITableView to the UIViewController for UIView, need not to induced above two lines of code
self.tbl_SlideMenu = [[UITableView alloc]
initWithFrame:CGRectMake(0, 80, self.view.frame.size.width,self.view.frame.size.height) style:UITableViewStylePlain];
[self.view addSubview:self.tbl_SlideMenu];
Once I included the allocation and added to subview its showing the data with tableview.
Once I removed allocation and frame added to subview is not visible.
So what is need of storyboard where I added UITableView to UIViewController for UIView (view default.) once Component added to storyboard and framed need not to allocate and frame in code.
Advance Thanks
Hope for best posible answers
If u added the tableview in storyboard there is no need to initialise the view components in the code in this case u don't need below lines as u mentioned
self.tbl_SlideMenu = [[UITableView alloc]
initWithFrame:CGRectMake(0, 80, self.view.frame.size.width,self.view.frame.size.height) style:UITableViewStylePlain];
however u need to create a outlet for your tableview to access the tableview in code that means as soon as view is loaded all your view components are initialised in your case tableview is initialised and u can ready to use it and also u don't need below lines of code if u set datasource and delegate in storyboard
self.tbl_SlideMenu.dataSource=self;
self.tbl_SlideMenu.delegate=self;
since u configured your tableview datasource and delegate and also added tableview to view controller's view there is no need of below line also
[self.view addSubview:self.tbl_SlideMenu];
and second way is as u mentioned creating the view in pure code, in this case u have to do all things by your self from initialising to adding the view component to controller's view as u mentioned like below
self.tbl_SlideMenu = [[UITableView alloc]
initWithFrame:CGRectMake(0, 80, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStylePlain]; //creating the tableview
self.tbl_SlideMenu.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
self.tbl_SlideMenu.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; //configuring the view
self.tbl_SlideMenu.separatorColor = [UIColor lightGrayColor];
self.tbl_SlideMenu.dataSource=self; //setting the datasource and delegate
self.tbl_SlideMenu.delegate=self;
[self.view addSubview:self.tbl_SlideMenu]; //adding it to tableview
hope u get this
Edit
it is working fine for me, i crossed checked it with some dummy values, for example as i mentioned , dragged and dropped a tableview, set its datasource and delegate to View Controller in storyboard and connected a outlet in ViewController.h file, like below,
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tbl_SlideMenu;
#end
and in ViewController.m file
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.tbl_SlideMenu.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.tbl_SlideMenu.separatorColor = [UIColor lightGrayColor];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CELL"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CELL"];
}
cell.textLabel.text = #"Hello";
return cell;
}
#end
and i got output showing the tableview with 5 "Hello" on each row

UITableView from separate class

Case is following: I want to create UITableView from separate class.
Currently I have following:
// Menu.h
#interface Menu : UITableViewController <UITableViewDelegate, UIAlertViewDelegate> {
UITableView *tableView;
}
#property (nonatomic,retain) NSMutableArray *navigationItems;
- (void)initMenu:(UIView *)view;
#end;
Then
// Menu.m
#import <Foundation/Foundation.h>
#import "Menu.h"
#implementation Menu
- (void) initMenu:(UIView *)view {
self.navigationItems = [[NSMutableArray alloc] initWithObjects:#"One",#"Two",#"Three",#"Four",#"Five",#"Six",#"Seven",#"Eight",#"Nine",#"Ten",nil];
UIView *mainmenu=[[UIView alloc]initWithFrame:CGRectMake(0, 50, 320, 420)];
[mainmenu setBackgroundColor:[UIColor yellowColor]];
[view addSubview:mainmenu];
UITableView *menutableView = [[UITableView alloc] initWithFrame:view.bounds style:UITableViewStylePlain];
menutableView.backgroundColor = [UIColor whiteColor];
menutableView.delegate = self;
menutableView.dataSource = self;
[mainmenu addSubview:menutableView];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableViewi cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableViewi dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [self.navigationItems objectAtIndex:indexPath.row];
return cell;
}
#end
And in different .m file I call method:
...
#import "Menu.h"
...
- (void)viewDidLoad
{
[super viewDidLoad];
...
Menu *menu = [[Menu alloc] init];
[menu initMenu: self.view];
}
Running this will crash application and Xcode won't give any detailed report. However, if I combine Menu.m to the .m file where I'm calling "initMenu" it won't crash.
Also if I comment out menutableView.dataSource = self; it will run with our crash (no rows in table of course...).
Passing a view into an init method and then creating/adding subviews in said init method is an odd design pattern. Change your Menu class to a viewcontroller, then move your UIView and UITableView declarations to the viewDidLoad method. The crash is likely happening because the tableview is trying to display data before its parent view has finished loading.

How can I return a TableView from a instance method?

I am trying to add a TableView as a subview in my RootViewController.The TableView will come from another ViewController(TableViewGeneratorController) instance method.
So,What is the best way to do this?
I have created a TableViewGeneratorController it works fine as a standalone app. Then from my RootViewController I have created one instance of the TableViewGeneratorController and trying to call the instance method prepareField,which will return the TableView. I got the TableView but
numberOfRowsInSection and cellForRowAtIndexPath is not getting called.
TableViewGeneratorController.h
#import <UIKit/UIKit.h>
#interface TableViewGeneratorController:UIViewController<UITableViewDataSource,UITableViewDelegate>
{
UITableView *tableView;
}
#property(strong,nonatomic)UITableView *generatedTbleView;
- (UITableView *)prepareField;
#end
TableViewGeneratorController.m
#import "TableViewGeneratorController.h"
#import "RootViewController.h"
#interface TableViewGeneratorController (){
}
#end
#implementation TableViewGeneratorController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (UITableView *)prepareField
{
tableView = [[UITableView alloc]initWithFrame:CGRectMake(10, 80, 300, 500)];
tableView.dataSource = self;
tableView.delegate = self;
tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
[tableView reloadData];
return tableView;
}
#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{
static NSString *cellIndentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIndentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIndentifier];
}
cell.textLabel.text = #"Yes";
return cell;
}
#end
RootViewController.m
Here I am trying to add the TableView as a subview.
TableViewGeneratorController *tableViewGeneratorController = [[TableViewGeneratorController alloc]initWithNibName:#"TableViewGeneratorController" bundle:nil];
UITableView *tv = [tableViewGeneratorController prepareField];
[self.view addSubview: tv];
What is the problem going on?
Thanks
What you are doing is not really the proper way.
The immediate issue is that the TableViewGeneratorController instance that you create goes out of scope and is deallocated. This leaves the table view with not existing data source or delegate. A simple workaround is to assign the TableViewGeneratorController instance to an instance variable instead of a local variable.
But the proper solution is to embed the TableViewGeneratorController as a child controller of the root view controller.
Change TableViewGeneratorController to be a UITableViewController and get rid of the prepareField method.
Then when you create the TableViewGeneratorController, you add it as a child controller. See the docs for UIViewController for details.

View Controller loading all table views cells instead of the first ones

Here is a simplified version of my controller. I'm creating a table view and I initialize this controller with a core data query that returns an array of around 300 objects.
I simplified the code here by hardcoding the height of each cell to 100.0f. Instead of only loading the first 5-6 cells that are actually visible on the screen on first load, the call to heightForRowAtIndexPath is actually done 300 times (for all cells), which makes the UI slow to load.
Any idea what I might be doing wrong here?
#interface PortsViewController () <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) UITableView *tableView;
#end
#implementation PortsViewController
#pragma mark - setters
- (void)setPorts:(NSArray *)ports
{
_ports = ports;
}
#pragma mark - Controller Methods
- (id)init
{
self = [super init];
self.screenName = kPortsListPage;
NSArray *ports = [Port MR_findAllSortedBy:#"name" ascending:TRUE];
[self setPorts:ports];
return self;
}
- (void)loadView {
self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self loadTableView];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.title = #"Ports";
}
#pragma mark - Load Helpers
-(void)loadTableView {
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:self.tableView];
}
#pragma mark - UITableViewDataSource Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.ports count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
PortTableViewCell* cell = [table dequeueReusableCellWithIdentifier:#"port"];
if (!cell) {
PortTableViewCell* cell = [[PortTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"port"];
}
cell.port = self.ports[indexPath.row];
return cell;
}
#pragma mark - UITableViewDelegate Methods
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"here");
return 100.0f;
}
#end
The table view needs to know it's total height. if you implement heightForRowAtIndexPath: it will be called for every row so the table know how tall it is.
If every row has the same height, simply set the rowHeight property on the table view instead of implementing the heightForRowAtIndexPath delegate method.
If each row can have a different height, then there is little you can other than making your implementation of heightForRowAtIndexPath as efficient as possible.
As of iOS 7, there is now the estimatedRowHeight property on UITableView. Using that should help improve things.

UITableViewCell.showingDeleteConfirmation gives NO when the delete-confirmation button is shown

I swipe on a table view cell to reveal the delete-confirmation button. But once I lift my finger, showingDeleteConfirmation gives NO even if the button is still there. (It does give YES when the button is showing up, I mean, before I lift my finger.) Am I missing something, or it's a real bug in iOS?
Following is my test code. (Copy&paste it into ViewController.m of a single-view project and run it in the simulator, and shift+command+M to trigger the NSLog.)
#import "ViewController.h"
#interface ViewController () <UITableViewDataSource, UITableViewDelegate>
#end
#implementation ViewController {
UITableViewCell *_myCell;
}
- (void)viewDidLoad
{
[super viewDidLoad];
UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 100, 320, 200)];
myTableView.dataSource = self;
myTableView.delegate = self;
[self.view addSubview:myTableView];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
_myCell = [[UITableViewCell alloc] init];
_myCell.contentView.backgroundColor = [UIColor greenColor];
return _myCell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
NSLog(#"_myCell.showingDeleteConfirmation = %#", _myCell.showingDeleteConfirmation ? #"YES" : #"NO");
}
#end
According to documentation:
Returns whether the cell is currently showing the delete-confirmation button. (read-only)
...
When users tap the deletion control (the red circle to the left of the cell), the cell displays a "Delete" button on the right side of the cell
So first you need to make grid editable
[myTableView setEditing:YES];
then user taps circle to delete (they not able to swipe left in this mode), and voilĂ :
_myCell.showingDeleteConfirmation = YES
While you can expect to use it as you described in your question, they don't promise it.

Resources