I want to create a custom tableView class, Which can be used in any view Controller. I have to just create tableview object and set an array and frame of tableview . Then this tableview will be add as subview on my view. and also give me a click event.
I just want to avoid writing tableview datasource and delegate method in every viewController class.
Take a viewController or tableviewController class and code all the delegates and data source methods there. now in you view controller where you want to make it as a subview call the tableview class and add it as a subview.
EX:
TableviewContrller *libaray =[TableviewContrller new];
[libaray willMoveToParentViewController:self];
[self.view addSubview:libaray.view];
[self addChildViewController:libaray];
To hide write this code in your tableview controller class
[self.view removeFromSuperView];
As you are using a reusable class you need to send the array information to that class. along with it it will be better to send either class name or setting tag value to tableview
So in your tableview class write this
-(id)initWithInformationArray :(NSMutableArray *)dataArray andTagValueforTableview :(int) tagValue
{
self = [super init];
if (self != nil)
{
NSLog(#"%#", dataArray);
}
return self;
}
Now sub viewing will be like this
TableviewContrller *libaray =[[TableviewContrller alloc]initWithInformationArray:YOURARRAY andTagValueforTableview:TAGVALUE];
[libaray willMoveToParentViewController:self];
[self.view addSubview:libaray.view];
[self addChildViewController:libaray];
Hope this will help.
May be you can use UITableViewController.
UITableViewController is a subclass of UIViewController, when you create a subclass of UITableViewController, the template has the usual methods of tableview datasource and delegate methods.
You'll need to create a custom class and create your own delegate in that class for UITableView. Now whenever you create a UITableView assign that custom class as the class for UITableView.
If you don't know how to create custom delegates then check below links:
http://www.alexefish.com/post/522641eb31fa2a0015000002
http://ios-blog.co.uk/tutorials/quick-tip-create-your-own-objective-c-delegate-protocol/
Hope this will help you :)
You can create BaseTableView class.
#interface BaseTableView : UITableView <UITableViewDelegate, UITableViewDataSource>
{
NSArray* listObject;
}
#property (nonatomic, retain) NSArray *listObject;
-(id) initWithFrame:(CGRect)frame style:(UITableViewStyle)style;
#end
#implementation BaseTable
#synthesize listObject;
-(id) initWithFrame:(CGRect)frame style:(UITableViewStyle)style
{
if(self = [super initWithFrame:frame style:style])
{
self.dataSource = self;
self.delegate = self;
}
return self;
}
-(void)setListObject:(NSArray *)listObjectRef
{
[listObject release];
listObject = [listObjectRef retain];
[self reloadData];
}
-(void) dealloc
{
[listObject release];
[super dealloc];
}
#end
Inherit this class for specific use and override following methods according to needs
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
In your ViewController class use following code
SpecificTableView *table = [[SpecificTableView alloc] init];
[table setListObject:((FRFTReportList*)obj)];
Hopefully this will help.
Related
There are a huge number of questions relating to this topic but I have not yet come across my use case so here goes.
This is my first couple weeks in OBJ-C so I have no clue what I am doing with some of this stuff...
What I Want
I do not particularly enjoy seeing so many classes in OBJ-C that overload the view controller classes with every and any function on this earth. It looks dirty and feels gross as far as OOP goes. In my use case I don't have a full screen table just a little one to hold 10 things. Therefore it's quite inappropriate to use a full UITableViewController. Instead, I want to have all my table delegate specific methods to be in a UITableView sub-class. NOT in a UITableViewController or a ViewController with a UITableView property. This should be mega simple yet...
The Problem
No matter what I do I cannot seem to get the method cellForRowAtIndexPath to fire. I know enough to know that this stuff relies heavily on the delegate and datasource assignment... however since I have a separate UITableView class that uses the <UITableViewDelegate, UITableViewDataSource> delegations I don't think I should have to do any sort of assignment at all!
What am I gonna write?? self.delegate = self ? or worse, in the ViewController that calls this UITableView class, self.tasksTable.delgate = self.tasksTable ? Eww... gross
Here is what I am doing in code.
The Code
TasksTableView.h
#import <UIKit/UIKit.h>
#interface TasksTableView : UITableView <UITableViewDelegate, UITableViewDataSource> {
NSArray *tasksData;
}
- (NSMutableArray *)getAllTasks;
#end
TasksTableView.m
#import "TasksTableView.h"
#import "NSObject+RemoteFetch.h" //<--I use this to fetch, obvs
#interface TasksTableView ()
#property (nonatomic, strong) NSString *cellId;
#end
#implementation TasksTableView
- (instancetype)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if(self) {
_cellId = #"AllTasksTableCell";
tasksData = [self getAllTasks];
}
return self;
}
#pragma mark - Custom Table Functionality
- (NSMutableArray *)getAllTasks {
#try {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *TASKS_URL = [userDefaults objectForKey:#"tasksUrl"];
NSObject *fetcher = [[NSObject alloc] init];
NSDictionary *response = [fetcher fetchAPICall:TASKS_URL httpRequestType:#"GET" requestBodyData:nil];
return [response objectForKey:#"data"];
} #catch (NSException *exception) {
NSLog(#"could not get tasks, error: %#", exception);
return nil;
}
}
#pragma mark - UITableView DataSource Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [tasksData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//<-- NEVER GETS HERE
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:_cellId];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:_cellId];
}
cell.textLabel.text = [tasksData objectAtIndex:indexPath.row];
return cell;
}
#end
I am also having a hard time figuring out what to set as the datasource. In other languages you would typically set the DataSource object with self.DataSource = [self getAllTasks]... however all the tuturials I have done thus far all tend to use some weird ad-hoc NSArray or NSDictionary to then correlate the index of the table functions with the index of the array or dictionary keys... This confuses me greatly as to why I can't just set the DataSource object and have the table know to iterate over it's data.
My conclusion is that this isn't firing because it thinks the DataSource object is empty and there are no rows? (which it is, but like I said people seem to get Tables to work fine on YouTube doing this)
Thanks.
TasksTableView class is derived from UITableView class & You are implementing the UITableview delegates in the same class. This will not work.
Instead of creating a UITableView subclass. Create TasksTableView class as NSObject sub class. And pass the tableview object from where you added a tableview.
#interface TasksTableView : NSObject <UITableViewDelegate, UITableViewDataSource> {
NSArray *tasksData;
__weak UITableView *tableView;
}
And set that table view delegate to self(TasksTableView object) while init the TasksTableView Class
- (instancetype)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if(self) {
_cellId = #"AllTasksTableCell";
tasksData = [self getAllTasks];
self.tableView.delgate = self;
self.tableView.datasource = self;
}
return self;
}
Now your delegate methods will trigger for that specific tableview
I'm new to iOS development. My Main View Controller doesn't display any cells from its table view. I was trying to set it up to display just one cell for now. The main view controller is a subclass of the UIViewController, and has a table view with the prototype cell as well. So my MainViewController.h file looks like below:
#import <UIKit/UIKit.h>
#interface MainViewController : UIViewController <UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UIBarButtonItem *sidebarButton;
#end
I made the MainVewController a delegate of the UITableViewDataSource, is that the right idea here? My MainViewController.m looks like below:
#import "MainViewController.h"
#import "SWRevealViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Home";
SWRevealViewController *revealViewController = self.revealViewController;
if(revealViewController) {
[self.sidebarButton setTarget: self.revealViewController];
[self.sidebarButton setAction: #selector(revealToggle:)];
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}
}
- (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 1; //change to number of post objects in array (array.count)
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"basicCell" forIndexPath:indexPath];
return cell;
}
#end
I don't understand what I'm doing wrong here. Shouldn't my MainViewController's Table View be properly displaying the cell? Thoughts?
You should use in viewDidLoad:
[self.tableView setDelegate:self];
[self.tableView setDataSource:self];
I don't see the Table View outlet. Did you forget to connect the Table View from interface builder to your view controller header file? After doing that you should also assign the delegate and data source properties of the table view to "self".
Your class just conforms to <UITableViewDataSource>
you should also conform UITableViewDelegate do it this way.
#interface MainViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
You missed setting the delegate and dataSource
It can be done in 2 ways:
using code:
[self.tableView setDelegate:self];
[self.tableView setDataSource:self];
put this code in viewDidLoad:
using storyboard: ctrl drag from tableView to your ViewController and set it as delegate and dataSource. see the Image below.
EDIT:
Why don't we need to connect the table's cell as well?
Ans: Table cell is returned from dataSource method tableView:cellForRowAtIndexPath:. This cell is displayed in the tableView. So we don't connect it in the storyboard. However we can configure it in the storyboard.
What's the difference between data source and delegate?
Ans: Delegate: The delegate is an object that is delegated control of the user interface for that event.
Datasource: A data source is like a delegate except that, instead of being delegated control of the user interface, it is delegated control of data.
For more information see Delegates and Data Sources and this answer.
I have 2 UIViewControllers, the 2 ones are containing EXACTLY the SAME UITableView(with its custom cells and delegate methods).
My question is their any way to "centralize" the UITableView UI and code(datasource and delegates), so that I just have to modify in one file instead of 2 .
following up on my comment, the table view in the xib in your father vc and the delegate methods in your father vc are just in the same place because you chose it to be like that, the table view and the delegate methods are actually quite detached.
so create a new object, say FatherTableController which implements UITableViewDatasource and UITabelViewDelegate and copy those methods out of your FatherViewController into this FatherTableController
now in your FatherViewController, go like
FatherTableController tableController = [FatherTableController new]; //should be a property or a singleton
self.tableview.delegate = tableController;
self.tableview.datasource = tableController;
now you can do that in both your separate vc's that use the same table, and even use the exact same table contoller between the two views if you share it in some way (possibly via a singleton pattern, which can be useful for sharing state between the two view controllers)
Solution:
#interface FatherViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
#property (strong, nonatomic) IBOutlet UITableView *parentTableView;
#implementation FatherViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.parentTableView.delegate=self;
self.parentTableView.dataSource=self;
}
//declare the delegate / datasource methods
--------------------- CHILD VIEW CONTROLLER ---------------------
#interface ViewController : FatherViewController
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.delegate=self;
self.tableView.dataSource=self;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [super numberOfSectionsInTableView:tableView];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [super tableView:tableView numberOfRowsInSection:section];
}
I have a custom cell with a label that should trigger a method of parent/table view controller.
Even though XCode provides me that method in autocomplete suggestions, it throws an error when I tap on that particular label:
UITableViewWrapperView showUserProfile unrecognized selector sent to instance
This is my code:
#implementation ItemTableViewCell
#synthesize item;
- (void)awakeFromNib
{
self.authorLabel.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(showUserProfile)];
[self.authorLabel addGestureRecognizer:tap];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
}
- (void)showUserProfile
{
id parentView = [self superview];
[parentView showUserProfile];
}
#end
Thanks!
it is not the good way to passing some actions to the tableview. You must use a delegate between the custom class UITableViewCell and your controller.
In your custom UITableViewCell.h
#protocol myUITableViewCellDelegate
#interface myUITableViewCell : UITableViewCell
#property (nonatomic, assign) id<myUITableViewCellDelegate> delegate;
#end
#protocol myUITableViewCellDelegate <NSObject>
-(void) cellDidTap:(myUITableViewCell*) sender
#end
In your custom UITableViewCell.m
...
- (void)showUserProfile
{
[self.delegate cellDidTap:self];
}
...
In your controller
-(UITableViewCell*) tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexpath
{
......
cell.delegate = self
......
}
-(void) cellDidTap:(myUITableViewCell*) sender
{
[self showUserProfile];
}
There is a difference between a view and a view controller. A view controller's class is UIViewController (or a subclass) and it has a property view of class UIView which it controls and which is the "visible part" of the view controller.
In the method
- (void)showUserProfile
{
id parentView = [self superview];
[parentView showUserProfile];
}
you call showUserProfile on the table view cell's superview but not on the view controller. As you don't know the internal implementation of a UITableView you cannot even be sure that the cell's superview is the same as your table view controller's view. In fact, it is not. Because as you can see from the error log the table view itself has a subview of class UITableViewWrapperView which contains all the cells. But this view doesn't know anything about the method you declared in your table view controller. That is why the app crashes.
For calling a method in your table view controller you can either declare a delegate as suggested by tdelepine or you can add an action to your button in your table view controller's tableView:cellForRowAtIndexPath: method right after dequeuing the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ItemTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"yourID"];
[cell.yourButton addTarget:self action:#selector(showUserProfile) forControlEvents:UIControlEventTouchUpInside];
// customize other properties of your cell
return cell;
}
This would be the easiest way to go in my opinion.
You can add the controller (your ViewController that hosts UITableView for example) to your customized cell. Then, you use something like:
if ([self.controller respondsToSelector:#selector("afunctioname")]) {
[self.controller performSelector:#selector("afunctionname")];
}
Your customizedCell: MyTableViewCell header
#property (nonatomic, assign) id controller;
In the method cellforRow;
MyTableViewCell *aCell = ...
aCell.controller = self
..
return aCell;
You can add parameters to this selector if the 'afunctioname' takes parameters. If you have multi parameters, use NSDictionary as parameter.
I am having a hard time communicating data between two view controllers that are inside a UISplitViewController. I am following this tutorial. I was able to create a split view controller with UITableViews on both master and detail views. Now, What I really want is that when I tap on a particular row in the master table, it has to send some value to the detail view.
I am just playing around with a custom delegate to pass some value from one view controller to another to see if there is any communication between them but nothing seems to work any way.
In MasterTableView.h
#protocol sendingProtocol <NSObject>
-(void)passSomeValue:(NSString *)someValue;
#end
#interface MasterTableView : UITableViewController
{
NSArray *menuArray;
id<sendingProtocol>delegate;
}
#property (nonatomic,assign) id<sendingProtocol>mydelegate;
#end
Synthesized in .m file.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[self mydelegate] passSomeValue:#"Some Value"];
}
In DetailTableView.h
-(void)passSomeValue:(NSString *)someValue
{
NSLog(#"%#", someValue);
}
Please note that I am calling the mydelegate inside the ViewDidLoad method. Is this the write way? Can someone help?
- (void)viewDidLoad
{
[super viewDidLoad];
MasterTableView *masterView = [[MasterTableView alloc] init];
masterView.mydelegate = self;
}
Thank you in advance!
In viewDidLoad method of your DetailTableView you should not create a new MasterTableView object. The error is here in this method:
- (void)viewDidLoad
{
[super viewDidLoad];
MasterTableView *masterView = [[MasterTableView alloc] init];
masterView.mydelegate = self;
}
You are creating another object of MasterTableView and setting its delegate to self and hence all the problem.
To set the delegate of MasterTableView to DetailTableView, go to AppDelegate.h. You must have defined the MasterTableView and DetailTableView objetcs in AppDelegate.
//Set the DetailTableView as the master's delegate.
self.masterTableView.delegate = self.detailTabelView;