I have a peculiar problem. I created a normal Objective C class called SampleTable. I then extended UITableView instead of NSObject. Then in the initWithFrame constructor I initialized the table. I also made a NSMutableArray object for the datasource. I also conformed UITableViewDelegate and UITableViewDatasource. I have overridden the necessary methods also.
Now I made an object of this class in another class, and added the object as a subview. The tableView is getting drawn according to the CGRectMake() coordinates I gave to the initWithFrame constructor. But it is not getting populated with the data. I don't know what the problem is.
SampleTable.h
#import <Foundation/Foundation.h>
#interface SampleTable : UITableView {
NSMutableArray *ItemArray;
}
#property (nonatomic,retain) NSMutableArray *ItemArray;
-(NSMutableArray *) displayItemArray;
#end
SampleTable.m
#import "SampleTable.h"
#implementation SampleTable
#synthesize ItemArray;
-(id)initWithFrame:(CGRect)frm {
[super initWithFrame:frm];
self.delegate=self;
self.dataSource=self;
[self reloadData];
return self;
}
-(NSMutableArray *) displayItemArray {
if(ItemArray==nil) {
ItemArray=[[NSMutableArray alloc] initWithObjects:#"1",#"2",#"3",#"4",#"5",nil];
}
return ItemArray;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [ItemArray count];
}
-(UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell= [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
[cell autorelease];
}
NSString *temp=[self.ItemArray objectAtIndex:indexPath.row];
cell.textLabel.text = temp;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"didselect");
}
-(void) dealloc {
[ItemArray release];
[super dealloc];
}
#end
You did never initialize the ItemArray within your code snippet. Remove the displayItemData method and change the initializer towards:
-(id)initWithFrame:(CGRect)frm
{
if ((self = [super initWithFrame:frm])) != nil)
{
self.delegate=self;
self.dataSource=self;
ItemArray=[[NSMutableArray alloc] initWithObjects:#"1",#"2",#"3",#"4",#"5",nil];
[self reloadData];
}
return self;
}
You could also simply call that displayItemArray method within the initializer. I feel that method makes no sense as it stands and hence my recommendation to remove it altogether.
Without trying it myself, I am still pretty confident that you can also get rid of that [self reloadData] within the initializer.
During the -(id)initWithFrame:(CGRect)frm method your code calls -reloadData on the UITableView. At this point in time your ItemArray is not available.
Therefore, when UITableView calls it's delegates -numberOfSectionsInTableView: and -tableView:numberOfRowsInSection: methods to get information on what to display in the view, they return one section with zero rows.
Nothing displayed!
It might be a (one) solution to change your initialization of the ItemArray:
-(NSMutableArray *) displayItemArray {
if(ItemArray==nil) {
ItemArray=[[NSMutableArray alloc] initWithObjects:#"1",#"2",#"3",#"4",#"5",nil];
[self reloadData];
}
return ItemArray;
}
print value of
[self.ItemArray objectAtIndex:indexPath.row];
in NSLog... check wether it prints valid value or not....It seems that array's object releasing somewhere before it..
Related
This is my scenario,
I have ViewController1 and Class1(Service Class).
I am loading tableView in nib by setting delegate and datasource in ViewController1. In viewDidLoad, i am calling a networkCall function in another class(Class1). In Class1, After getting a response it will pass an array of response data to a function in ViewController1 where the data should be populated in tableview.
i have connected datasource and delegate in xib.
Problem:
When i get a response as an array in ViewController1, UITableView becomes nil, i cannot able to use reloadData, but my array contains list of items from server.
Here's my code
ViewController1
- (void)viewDidLoad
{
[super viewDidLoad];
ClassA *class = [[ClassA alloc]init];
[class getResponse];
}
//This method is calling from ClassA using delegate
-(void)responseData:(NSArray*)arrayList
{
//arrayList have response data
[tableView reloadData];//here tableView becomes nil.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"array count %d",array.count);//has number of items(for me, its 3).
return array.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TableView";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = #"dsds";
return cell;
}
tableView is calling first time.
In ViewController1
in interface, i am setting protocols
<UITableViewDelegate,UITableViewDataSource>
You are creating new instance of ViewController1 instead of using the one that has been loaded.
you can do the following:
for ClassA:
interface:
#interface ClassA : ...
#property (weak) ViewController1 * vcDelegate;
...
#end
implementation:
#implementation ClassA
#synthesize vcDelegate;
...
#end
and instead of
id<ViewController1Protocol>view1 = [[ViewController1 alloc]init];
[view1 responseData:objects];
call
[vcDelegate responseData:objects];
In your ViewController, when creating ClassA you need to set delegate to self:
- (void)viewDidLoad
{
[super viewDidLoad];
ClassA *class = [[ClassA alloc]init];
[class setVcDelegate: self];
[class getResponse];
}
It's not the best implementation, but should give you idea of how to do it.
For example, property should probably be
#property (weak) id<ViewController1Protocol> vcDelegate;
You have to connect your tableView with the table view in the xib.
The red region in the image is not connected with your table view. It is empty.
This is my problem:
I have this small UITableView in my storyboard:
And this is my code:
SmallTableViewController.h
#import <UIKit/UIKit.h>
#import "SmallTable.h"
#interface SmallViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITableView *myTable;
#end
SmallTableViewController.m
#import "SmallViewController.h"
#interface SmallViewController ()
#end
#implementation SmallViewController
#synthesize myTable = _myTable;
- (void)viewDidLoad
{
SmallTable *myTableDelegate = [[SmallTable alloc] init];
[super viewDidLoad];
[self.myTable setDelegate:myTableDelegate];
[self.myTable setDataSource:myTableDelegate];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
Now as you can see, I want to set an instance called myTableDelegate as Delegate and DataSource of myTable.
This is the Source of SmallTable class.
SmallTable.h
#import <Foundation/Foundation.h>
#interface SmallTable : NSObject <UITableViewDelegate , UITableViewDataSource>
#end
SmallTable.m
#implementation SmallTable
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
cell.textLabel.text = #"Hello there!";
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Row pressed!!");
}
#end
I implemented all the UITableViewDelegate and UITableViewDataSource method that the app need. Why it just crash before the view appear??
Thanks!!
rickster is right. But I guess you need to use a strong qualifier for your property since at the end of your viewDidLoad method the object will be deallocated anyway.
#property (strong,nonatomic) SmallTable *delegate;
// inside viewDidload
[super viewDidLoad];
self.delegate = [[SmallTable alloc] init];
[self.myTable setDelegate:myTableDelegate];
[self.myTable setDataSource:myTableDelegate];
But is there any reason to use a separated object (data source and delegate) for your table? Why don't you set SmallViewController as both the source and the delegate for your table?
In addition you are not creating the cell in the correct way. These lines do nothing:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
cell.textLabel.text = #"Hello there!";
dequeueReusableCellWithIdentifier simply retrieves from the table "cache" a cell that has already created and that can be reused (this to avoid memory consumption) but you haven't created any.
Where are you doing alloc-init? Do this instead:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell) {
cell = // alloc-init here
}
// Configure the cell...
cell.textLabel.text = #"Hello there!";
Furthermore say to numberOfSectionsInTableView to return 1 instead of 0:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
Presumably you're using ARC? Your myTableDelegate is only referenced in a local variable in viewDidLoad -- once that method ends, it's deallocated. (In the delegate/datasource pattern, objects do not own their delegates, so the table view's references back to your object are weak.) I wouldn't expect that alone to cause a crash, but it's likely key to your problem.
setDelegate will not retain the delegate.
And
numberOfSectionsInTableView method has to return 1 instead of 0;
(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 0;
}
Number of sections should be set at least one
The delegate of an UITableView object must adopt the UITableViewDelegate protocol. Optional methods of the protocol allow the delegate to manage selections, configure section headings and footers, help to delete methods.

Im having a little issue with using more than 1 UITableView on a view.
Here's what I've done so far (using examples, etc from here and other places):
Created a class for each table. Each class is pretty basic:
.h:
#interface ConstructionDocumentsJobTable : UITableViewController <UITableViewDataSource, UITableViewDelegate> {
NSMutableArray *tableItems;
IBOutlet UITableView *itemsTable;
NSInteger recordSelected;
id <JobTableSelectionDelegate> tableSelectDelegate;
}
#property (nonatomic, retain) NSMutableArray *tableItems;
#property (nonatomic, assign) id <JobTableSelectionDelegate> tableSelectDelegate;
#end
.m:
#implementation ConstructionDocumentsJobTable
#synthesize tableItems, tableSelectDelegate;
#pragma mark -
#pragma mark View Life Cycle
-(void) loadView
{
}
-(void) dealloc
{
[tableItems release];
[super dealloc];
}
#pragma mark -
#pragma mark Table view data source
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [tableItems count];
}
// Customize the appearance of table view cells.
- (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] autorelease];
}
cell.textLabel.text = [tableItems objectAtIndex:indexPath.row];
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//pass the tap value back to the delegate
}
Both are completely identical, save the names.
When Im making the call to the first one, it is called in the ViewDidLoad method of the controller of the view. It's pretty basic:
NSMutableArray *tableItems = [[NSMutableArray alloc] initWithCapacity:intMax];
//strDocumentType is set elsewhere and loaded here
if(strDocumentType == #"typea"){
[tableItems addObject:#"Type A - Value 1"];
[tableItems addObject:#"Type A - Value 2"];
}
else {
[tableItems addObject:#"Type B - Value 1"];
}
if(jobTableController == nil){
jobTableController = [[ConstructionDocumentsJobTable alloc] init];
[jobTableController loadView];
jobTableController.tableItems = tableItems;
jobTableController.tableSelectDelegate = self;
}
[tableJobList setDataSource:jobTableController];
[tableJobList setDelegate:jobTableController];
jobTableController.view = jobTableController.tableView;
The second table is built when a cell in the first table is selected. So, in the first tables selection method, the delegate is called back from the parent controller, which then has this:
NSMutableArray *tableTypeItems = [[NSMutableArray alloc] initWithCapacity:100];
if(tableSelect == #"plumbing"){
[tableTypeItems addObject:#"Something"];
[tableTypeItems addObject:#"Other"];
}
if(typeTableController == nil){
typeTableController = [[ConstructionDocumentsTypeTable alloc] init];
[typeTableController loadView];
typeTableController.tableItems = tableTypeItems;
typeTableController.tableSelectDelegate = self;
}
[tableTypeList setDataSource:typeTableController];
[tableTypeList setDelegate:typeTableController];
typeTableController.view = typeTableController.tableView;
[typeTableController.tableView reloadData];
//Code to move the first table off the screen and move this one into view goes here
Ive been stuck on this for days, and I really need to get this done!!!
Im sure it's something REALLLLLLY simple.
Any help you guys can pass along would be HUGELY appreciated.
Thanks everyone.
Your only defining itemsTable in your header, try defining another table, and in your cellForRowAtIndexPath try this:
if(itemsTable1){
/* stuff for first table */
} else {
/* stuff for second table */
}
And do the same for each UITableVIew Delegate
I've subclassed UITableView to create my own data retrieval system, as described in Apple's own Core Data tutorial, but I've hit a problem. The substitute cellForRowAtIndexPath method in my custom table never gets called, not even when I call reloadData or setNeedsDisplay. I've been hunting around for solutions to this one, and it seems that this error can be caused by a multitude of problems. However I've checked all the ones I can find and cannot see anything missing. Can anyone tell me what's likely to be wrong?
P.S. I know the UITableViewDataSource protocol needs to be in triangular brackets, but I couldn't find out how to show triangular brackets on the page without deleting the text between them.
H-File
#interface DataTable : UITableView <UITableViewDataSource> {
NSMutableArray *list;
}
#property (nonatomic, retain) NSMutableArray *list;
#end
M-File
#implementation DataTable
#synthesize list;
-(id) initWithFrame:(CGRect)rect Style:(UITableViewStyle)style{
if (self = [super initWithFrame:rect style:style]){
list = [[NSMutableArray alloc] init];
self.dataSource = self;
}
return self;
}
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [list count];
}
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellID = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil){
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:cellID] autorelease];
}
CH *this = (CH *)[list objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [this.clusterName mutableCopy];
return cell;
}
-(void) dealloc{
[list release];
[super dealloc];
}
#end
Never mind, think I've found it. Basically, you can't set the datasource delegate in that part of the program. Need to do it from its owning view controller.
I want to use two tableviews under the segmentedcontrol. one is plain styled and the other is groupstyled. How can i controll the delegate and datasource for the two table views?
--
Regards,
Syed yusuf
HI,
I have to inserted the data into table view by using sqlite.But now i need that data in to two table views in next view..I have arranged segmented bar.Am getting two table views but the values in r not displaying.It is displaying NULL.
Using multiple or two exclusive table in the save UI view controller sharing the same data source.
I face a problem like this, if anybody needs later...
I try to set my ViewController as a datasource for two different table. But it did not work. 2 tables are exclusively shown at loadtime of the view. Either one will be hidden in viewDidLoad depending on a flag. Seems once dataSource is called for one table, it's not called for the 2nd table. All connections are set in IB.
The solution is to set the dataSource in code in viewDidLoad. Then it works.
-(void) viewDidLoad(){
table1.dataSource = self;
table2.dataSource = self;
if(someCondition == YES)
table1.visible = NO;
else
table2.visible = NO;
}
Since you can't change the UITableViewStyle of a UITableView once created (it can only be set at construction time), you have to have two different instances. You can do this in very different ways, but I've done it this way: add a UISegmentedControl to your interface, and set its target to the RootViewController class instance in your application. The RootViewController class could look like this:
#class DataSource;
#interface RootViewController : UITableViewController
{
#private
UITableView *_originalTableView;
UITableView *_secondaryTableView;
DataSource *_dataSource;
BOOL _showingSecondaryTableView;
}
- (IBAction)swap:(id)sender;
#end
And this might be the implementation:
#import "RootViewController.h"
#import "DataSource.h"
#implementation RootViewController
- (void)dealloc
{
[_dataSource release];
[_originalTableView release];
[_secondaryTableView release];
[super dealloc];
}
- (void)viewDidLoad
{
[super viewDidLoad];
_dataSource = [[DataSource alloc] init];
_secondaryTableView = [[UITableView alloc] initWithFrame:self.tableView.frame
style:UITableViewStyleGrouped];
_secondaryTableView.delegate = _dataSource;
_secondaryTableView.dataSource = _dataSource;
_originalTableView = [self.tableView retain];
_showingSecondaryTableView = NO;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark -
#pragma mark IBAction method
- (IBAction)swap:(id)sender
{
if (_showingSecondaryTableView)
{
self.tableView = _originalTableView;
_showingSecondaryTableView = NO;
}
else
{
self.tableView = _secondaryTableView;
_showingSecondaryTableView = YES;
}
}
#pragma mark -
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return 5;
}
- (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] autorelease];
}
cell.textLabel.text = [NSString stringWithFormat:#"RootViewController cell %d", indexPath.row];
return cell;
}
#end
This is the interface of the DataSource class:
#import <UIKit/UIKit.h>
#interface DataSource : NSObject <UITableViewDelegate,
UITableViewDataSource>
{
}
#end
And the implementation:
#import "DataSource.h"
#implementation DataSource
#pragma mark -
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"DataSourceCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [NSString stringWithFormat:#"DataSource cell %d", indexPath.row];
return cell;
}
#end
You can change the datasource and delegate of the UITableView instances to anything you want, at any time during runtime, which might help you encapsulate different data sources with separate controllers.
Hope this helps!