UITableView becomes Nil After getting response from server - iphone

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.

Related

Set UITableView Delegate and DataSource

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.


pass NSMutableArray to UITableViewController

I have UIViewController that contains NSMutableArray , I want to pass this array to UITableViewController and view it on the table .. how can I do that ??
I mean I want to (pass) NSMutableArray or any Variable from UIViewController to UITableViewController not (create) a table
I want to pass newBooksArray to UITableViewController, I wrote in UIViewController:
mytable.gettedBooks = newBooksArray; // gettedBooks is NSMutableArray in UITableViewController
mytable.try = #"Emyyyyy"; // try is a NSString in UITableViewController
and in UITableViewController in DidloadView i wrote
NSLog(#"Try: %#", try); // out is null
NSLog(#"my getted array count: %d", [gettedBooks count]); // out is 0
any help ???
Creating a UITableView and filling with an array
I created the above tutorial specially for this problem.
There are also more methods you can learn about on the developer documents
Firstly, you want to make sure you have the required delegate calls in your #interface:
#interface RootViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
NSMutableArray * feed;
UITableView * tableView;
}
You want something similar to the following in your controller:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [feed count];
}
- (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 = [mutableArray objectAtIndex:indexPath.row];
return cell;
}
numberOfRowsInSection makes sure you actually load the required number of cell rows from your NSMutableArray. And cellForRowAtIndexPath actually loads the content from each row of your NSMutableArray into each row of the UITableView.
For passing it to another controller, don't you want something like this?
UITableViewController *viewController = [[UITableViewController alloc] initWithNibName:#"TableXIB" bundle:nil];
[viewController setGettedBooks:newBooksArray];
[self.navigationController pushViewController:viewController animated:YES];
UITableview tutorial and sample code
Hope,this will help you..enjoy
If you are using a Tab Bar controller, and First View controller is table view controller and second is UIView controller. You can Pass data to Table View controller by followoing code segment. You need to declare variable called arrayData (NSMutableArray) in table view controller and set property (Since we need to access this from another class.) From this arrayData, you need to load data in tableView. In View controller class write following code.
NSArray *viewControllers = [self.tabBarController viewControllers];
MyTableViewController *mTable = [viewControllers objectAtIndex:0];
[mTable SetArrayData:arrayFromViewController];
[mTable.tableView reloadData];
If you are using Navigation controller, you can do
NSArray *viewControllers = [self.navigationController viewControllers];
MyTableViewController *mTable = [viewControllers objectAtIndex:0];
[mTable SetArrayData:arrayFromViewController];
[mTable.tableView reloadData];
Optionally you can use delegates.

Inserting data from one table to another table

I have two UITableViewController classes, MainTableController and SubTableController.
From AppDelegate class I am calling MainTableController class.
At first this class is empty, and there is button named "show list" in this class.
When I click on this button I will go to SubTableController and there I have a list of actions in form of table.
Now if I choose to first cell action then that action name has to come on my first cell of table in MainTableController. But I am not able to print that name in table of MainTableController class.
In SubTableController:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ActionList * actionListObj = [appDelegate.actionArray objectAtIndex:indexPath.row];
self.chooseActions = actionListObj.actionName;
MainTableController * mainViewController = [[MainTableController alloc] init];
[mainViewController getAction:self.chooseActions];
[self.navigationController dismissModalViewControllerAnimated:YES];
}
In MainTableController:
-(void) viewWillAppear:(BOOL)animated{
[self reloadData];
}
-(void) reloadData{
[self.myTableView reloadData];
}
-(void) getAction: (NSString *) actionChoose{
self.action = actionChoose;
[self reloadData];
}
-(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];
}
// Configure the cell...
cell.textLabel.text = self.action;
return cell;
}
When I debug, in MainTableController I am getting the action in getAction method but in table cell text string is null.
Can anyone please help me regarding this?Where am I going wrong?
You are allocating and initializing a new view controller each time you select a cell in SubTableController.
MainTableController * mainViewController = [[MainTableController alloc] init];
and of course, it isn't the one in place in the navigation stack.
You need to make these two controllers communicate.
I suggest that the sub view controller define a property on the main one, in order to message it when needed.
In SubTableController, add a property and synthesize it :
#property(readwrite, assign) MainViewController *mainViewController;
// and ...
#synthesize mainViewController;
Of course when you push the sub view controller, don't forget to set the property.
// in main view controller
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// alloc/init the sub VC
subVCInstance.mainViewController = self;
[self pushViewController:subVCInstance ......
Now when a row is selected in the sub one, message the main one, without alloc/init a new MainViewController object :
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ActionList * actionListObj = [appDelegate.actionArray objectAtIndex:indexPath.row];
self.chooseActions = actionListObj.actionName;
//MainTableController * mainViewController = [[MainTableController alloc] init];
[self.mainViewController getAction:self.chooseActions];
[self.navigationController dismissModalViewControllerAnimated:YES];
}
This should work just fine.
In didSelectRowAtIndexPath of the SubTableController class, you are allocating new MainTableController to send the data.
MainTableController * mainViewController = [[MainTableController alloc] init];
[mainViewController getAction:self.chooseActions];
You should not do like that. Because the existing mainview will be different from the newly allocated one. You should use delegate to give back the data. For more info on Protocols and delegates, see here
More example here

iOS: Custom UITableViewCell touch receiver confusion

have seen similar questions but couldn't find a definitive answer.
Having mastered regular tables of most types, I am doing some conceptual experiments with custom table cells to get familiar with how this works. I want to have a custom subclass of UITableViewCell which loads a nib to the contentView. I may want to implement different editing styles at some later point but want to reuse the custom view in different parts of my application, however, i'm having problem receiving the didSelectRowAtIndexPath message in my calling UITableViewController.
Here's the hierarchy which is built from a basic view template.
CustomCellViewController: A stock XCode objective-c class sublcassed from UITableViewCell
#interface CustomCellViewController : UITableViewCell {
IBOutlet UILabel *lbl;
}
#property (nonatomic, retain) IBOutlet UILabel *lbl;
#end
#implementation CustomCellViewController
#synthesize lbl;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
NSArray *a = [[NSBundle mainBundle] loadNibNamed:#"customCellView" owner:self options:nil];
UITableViewCell *tc = [a objectAtIndex:0];
NSLog(#"Cell loaded from nib");
[self.contentView addSubview:tc];
}
return self;
}
.. the other stock methods are unchanged ..
#end
I realise that the init method could be simplified but this is my first attempt.
The XIB file's owner is my custom class (CustomCellViewController), has a UITableViewCell and a label (linked to the outlet 'lbl' on it) positioned half way accross, leaving plenty of the underlying UITableViewCell clickable.
RootViewController is a standard, stock XCode subclass of UITableViewController
RootViewController sets up an instance variable "CustomTableCellController *myCustomCell"
The cellForRowAtIndexPath: is as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"myCustomCell";
CustomCellViewController *cell = (CustomCellViewController *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomCellViewController alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
NSLog(#"Creating New cell for position %d", indexPath.row);
} else {
NSLog(#"Reusing cell for position %d", indexPath.row);
}
// Configure the cell.
cell.lbl.text = [NSString stringWithFormat: #"Hi There %d", indexPath.row];
return cell;
}
And in the same RootViewController.m, my didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Cell tapped at row %d", indexPath.row);
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
}
Designed at present, to purely output a log message when tapped.
numberOfSectionsInTableView returns 1
numberOfRowsInSection returns 50
This all compiles and runs fine, iPhone simulator starts, I see a table on the display, my output log confirms it has created 9 versions of CustomCellViewController and I can see the reuse stack via the NSLog() comments.
I just can't select a row, doesn't matter where I click in the custom cell, nothing gets to my didSelectRowAtIndexPath: in my RootViewController which is where I expect it.
Is it that I have I not set a delegate somewhere and if so, how? Do I need to do this via a first responder? (ie, create a method in my CustomCellViewController class, link the UITableViewCell from the XIB to that method and then call [super didSelectRowAtIndexPath] - but how do I pass the indexPath?
Am I not responding to a message from my XIB in it's owner and then passing it on (is this how I do it?)
I read through all the apple docs to get to this stage but couldn't quite decipher how touch messaging happened.
Slightly confused!
May be you have forget to set data source and delegate if the tableview object set it as like below
tbl.delegate = self;
tbl.dataSource = self;

UITableView not getting populated

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..