When I load remote content via a block I update the UITableView by calling reloadData. However, I am unable to scroll on this data. I think this is because I have declared that the number of rows in the table is the length of my NSArray variable that will hold the contents of the list. When this is called though, the list has a count of zero. I would have assumed that by calling reloadData on the tableView that it would have recalculated the list size again.
Perhaps I'm missing a step along the way.
Thanks
Here is my code
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:
[NSURL URLWithString: #"MYURL"]];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
}
-(void) fetchedData:(NSData *)responseData
{
NSError* error;
id json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
self.dataList = json;
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self.tableView reloadData];
});
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.dataList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"SongCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
if([self.dataList count] > 0){
NSDictionary *chartItem = [self.dataList objectAtIndex:indexPath.row];
NSDictionary *song = [chartItem objectForKey:#"song"];
cell.textLabel.text = [song objectForKey:#"title"];
}
return cell;
}
Check that your json object (and therefore self.dataList) is not nil at the end of the asynchronous call. If it is, then [self.dataList count] will return 0.
Also, make sure that you correctly set self.dataList.dataSource.
This is working now.
The cause of the problem was the I had added a pan gesture to the UITableView
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
This seems to interfere with the ability to scroll on a table. Hopefully this will help anyone who comes across this in the future.
Related
I started an iOS project and I'm working with UITableView to display a list of pilots with images . I did pagination on my api and I tried to load more once you scrolled the tableview. the problem that I got is that the new cells are always displayed on top of the tableview not in the bottom. Please check on my code if there is a solution I will be grateful
- (void)loadData :(NSInteger)page {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
url = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#%#%ld",NSLocalizedString(#"get_pilots",nil),mainDelegate.idAccount,#"?page=",(long)page]];
task = [restObject GET:url :mainDelegate.token completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSMutableDictionary* jsonResponse = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:nil];
NSArray *pilotKey = [jsonResponse objectForKey:#"pilot"];
for (NSDictionary *pilotItem in pilotKey ){
PilotObject *pilotObj = [PilotObject new];
[pilotObj getPilot:pilotObj :pilotItem];
[_pilotsAll addObject:pilotObj];
}
dispatch_async(dispatch_get_main_queue(), ^{
[hud hideAnimated:YES];
[self checkTableView:_pilotsDisplay :self.view];
[viewPilots.tableViewPilots reloadData];
});
}];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (currentPage == totalPages) {
return [_pilotsDisplay count];
}
return [_pilotsDisplay count] + 1;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == [_pilotsDisplay count] - 1 && currentPage<totalPages ) {
[self loadData:++currentPage];
NSLog(#"current page : = %ld",(long)currentPage);
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == [_pilotsDisplay count]) {
static NSString *identifier = #"PilotCellTableViewCell";
PilotCellTableViewCell *cell = (PilotCellTableViewCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
cell.hidden=YES;
UIActivityIndicatorView *activityIndicator = (UIActivityIndicatorView *)[cell.contentView viewWithTag:100];
[activityIndicator startAnimating];
return cell;
} else {
PilotObject *pilotObjDisplay = nil;
pilotObjDisplay = [_pilotsDisplay objectAtIndex:[_pilotsDisplay count]-1-indexPath.row];
static NSString *identifier = #"PilotCellTableViewCell";
PilotCellTableViewCell *cell = (PilotCellTableViewCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
cell.hidden=NO;
cell.image.image = pilotObjDisplay.imageDisplayPilot;
cell.titleLabel.text = pilotObjDisplay.firstName;
cell.subTitleLabel.text = pilotObjDisplay.lastName;
cell.backgroundColor = [UIColor colorWithHexString:NSLocalizedString(#"gray_background", nil)];
return cell;
}
return nil;
}
Why you are taking 2 array _pilotsDisplay and _pilotsAll ?
If not necessary then you can also do pagination using one NSMutableArray which you can use in both cases while fetching data from server as well as while filling data to UITableView.
Remember one thing only initialise your NSMutableArray in viewDidLoad method. And when you received new data use addObject method of NSMutableArray which you are already using. And then call reloadData method of UITableView.
And in cellForRowAtIndexPath don't use calculation like [_pilotsDisplay count]-1-indexPath.row, simply use indexPath.row.
Here, inserting rows to the tableview may help you.
[tableView beginUpdates];
NSArray *paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:[dataArray count]-1 inSection:1]];
[[self tableView] insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationTop];
[tableView endUpdates];
You shouldn't add cells to a tableview. what you should do is add data to the tableview's datasource (in your case, _pilotsDisplay) and then simply reload the table. If you want the new data to appear at bottom or in any particular order, you should do that to your datasource (the array).
I'm trying to adjust height of UITableViewCell based on content after getting JSON data.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
I've added like that but UITableViewCell height cannot be increased based on content. Please help me how to solve.
- (void) getAllocatedJobs {
_allTableData = [[NSMutableArray alloc]init];
[SVProgressHUD show];
dispatch_queue_t getInit = dispatch_queue_create("getinit",NULL);
dispatch_async(getInit, ^{
NSDictionary *jsonResponse = [commClass getJobs:strDriverId paramJobType:#""];
NSNumber *status = [jsonResponse valueForKey:#"Success"];
NSString *message = [jsonResponse valueForKey:#"Message"];
NSArray *dataArray = [jsonResponse valueForKey:#"lstJob"];
dispatch_async(dispatch_get_main_queue(), ^{
if([status intValue] == 1) {
for(int i=0; i<[dataArray count]; i++) {
NSDictionary *JobData = [dataArray objectAtIndex:i];
[_allocatedTable reloadData];
} else {
[commClass showAlert:APP_NAME alertMessage:message];
[SVProgressHUD dismiss];
}
});
});
}
if you want to use UITableViewAutomaticDimension then don't return it in heightForRowAtIndexPath.Do it in viewDidload like,
tableView.estimatedRowHeight = 100.0
tableView.rowHeight = UITableViewAutomaticDimension
and autolayout is mandatory for UITableViewAutomaticDimension so make sure that you have set proper constraints. and reload table data when you get all json data successfully if needed.
Hope this will help :)
Try to calculate the height based on the content in this method:-
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
How send data to tableview in iOS with objective-C? I am trying to solve my problem very long time but result is not correct. My tableview is still empty. What I'm doing wrong? Below is my implementation file.
import "PlacesViewController.h"
#implementation PlacesViewController
#synthesize places;
- (void)viewDidLoad
{
[super viewDidLoad];
// Set this view controller object as the delegate and data source for the table view
self.listTableView.delegate = self;
self.listTableView.dataSource = self;
}
-(void)queryGooglePlaces
{
//Build the url string to send to Google
NSString *url = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=51.503186,-0.126446&radius=5000&types=food#|restaurant|bar&keyword=vegetarian&key=myOwnKEY"];
url = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(#"%#", url);
//Formulate the string as a URL object.
NSURL *googleRequestURL=[NSURL URLWithString:url];
// Retrieve the results of the URL.
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: googleRequestURL];
dispatch_sync(dispatch_get_main_queue(), ^{
[self fetchedData:data];
});
});
}
-(void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
//The results from Google will be an array obtained from the NSDictionary object with the key "results".
self.places = [json objectForKey:#"results"];
//Write out the data to the console.
NSLog(#"Google Data: %#", json);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.places count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSDictionary *tempDictionary= [self.places objectAtIndex:indexPath.row];
cell.textLabel.text = [tempDictionary objectForKey:#"name"];
return cell;
}
#end
Whenever you update the datasource, you need to call [self.tableView reloadData]
So it should be like this
-(void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
//The results from Google will be an array obtained from the NSDictionary object with the key "results".
self.places = [json objectForKey:#"results"];
// NOTE - ADDED RELOAD
[self.tableView reloadData];
//Write out the data to the console.
NSLog(#"Google Data: %#", json);
}
For more information about reloadData see the answer
After you update the data source you should reload the table view.
self.places = [json objectForKey:#"results"];
[self.tableView reloadData];
I hope you guys help me in my code which is load data from a website. Let's start with the code:
-(void)viewDidLoad
{
[self loadDataFromUrl];
}
-(void)loadDataFromUrl {
NSString *myUrl = [NSString stringWithFormat:#"http://WebSite/PhpFiles/File.php"];
NSURL *blogURL = [NSURL URLWithString:myUrl];
NSData *jsonData = [NSData dataWithContentsOfURL:blogURL];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization
JSONObjectWithData:jsonData options:0 error:&error];
for (NSDictionary *bpDictionary in dataDictionary) {
HotelObject *currenHotel = [[HotelObject alloc]initWithVTheIndex:
[bpDictionary objectForKey:#"TheIndex"] timeLineVideoUserName:
[bpDictionary objectForKey:#"timeLineVideoUserName"] timeLineVideoDetails:
[bpDictionary objectForKey:#"timeLineVideoDetails"] timeLineVideoDate:
[bpDictionary objectForKey:#"timeLineVideoDate"] timeLineVideoTime:
[bpDictionary objectForKey:#"timeLineVideoTime"] timeLineVideoLink:
[bpDictionary objectForKey:#"timeLineVideoLink"] timeLineVideoLikes:
[bpDictionary objectForKey:#"timeLineVideoLikes"] videoImage:
[bpDictionary objectForKey:#"videoImage"] timeDeviceToken:
[bpDictionary objectForKey:#"deviceToken"]];
[self.objectHolderArray addObject:currenHotel];
}
}
-(NSMutableArray *)objectHolderArray{
if(!_objectHolderArray) _objectHolderArray = [[NSMutableArray alloc]init];
return _objectHolderArray;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:
(NSInteger)section
{
return [self.objectHolderArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
Cell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
HotelObject *currentHotel = [self.objectHolderArray
objectAtIndex:indexPath.row];
cell.lblID.text = currentHotel.vvTheIndex;
cell.lblName.text = currentHotel.vvUserName;
cell.lblCity.text = currentHotel.vvVideoDate;
cell.lblAddress.text = currentHotel.vvVideoLikes;
return cell;
}
The above code is loading data from a Url and fill the TableView and this step working fine. The app has another ViewController which is DetailsView, in DetailsView users can update some info. When the user goes back to the TableView nothing happened (I mean the data still the same and not updated). I have tried to call the loadDataFromurl from ViewDidAppear but it does not work.
I did add:
[self.tableView reloadData];
But still the same result.
Her is also my NSObject code:
-(instancetype)initWithVTheIndex:(NSString *)vTheIndex
timeLineVideoUserName:(NSString *)vUserName
timeLineVideoDetails:(NSString *)vVideoDetails
timeLineVideoDate:(NSString *)vVideoDate
timeLineVideoTime:(NSString *)vVideoTime
timeLineVideoLink:(NSString *)vVideoLink
timeLineVideoLikes:(NSString *)vVideoLikes
videoImage:(NSString *)vVideoImage
timeDeviceToken:(NSString *)vDeviceToken {
self = [super init];
if(self){
self.vvTheIndex = vTheIndex;
self.vvUserName = vUserName;
self.vvVideoDetails = vVideoDetails;
self.vvVideoDate = vVideoDate;
self.vvVideoTime = vVideoTime;
self.vvVideoLink = vVideoLink;
self.vvVideoLikes = vVideoLikes;
self.vvVideoImage = vVideoImage;
self.vvDeviceToken = vDeviceToken;
}
return self;
}
My question is: How can I update the TableView when moving from DetailsView or even when I pull to refresh.
Thanks in advance
You are not properly reloading the data source of your UITableView.
Assuming the remote URL is getting updated with the new data, and the issue is only reloading the TableView, make sure you add your [self.tableView reloadData] AFTER loadDataFromUrl has finished.
The reloadData method will always refresh the table's content, so either it's not being called at the right time or you are not updating self.objectHolderArray. (You can debug that by setting a breakpoint after calling loadDataFromUrl after the update.)
on viewDidLoad lifecycle first [self.tableView reloadData] reload tableview then another work.
Well in my .m file I am doing the following:
I am fetching data over the web and store them in an NSMutable array by parsing json array. These data are images urls (images are on my server) and then I want to set them on my custom cell. each cell has 2 imageviews.
I am parsing the data correctly.
i do store them correctly.
I can see their values printed out and If i open them in a browser they are correct values.
If in my cell place static images from my resources I can see them.
But If i try to set them from the url I do not see anything.
here is my code:
For fetching data:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"connectionDidFinishLoading");
NSLog(#"Succeeded! Received %d bytes of data",[self.responseData length]);
// convert to JSON
NSError *myError = nil;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&myError];
images_url= [NSMutableArray new];
for (NSDictionary *alert in json ){
NSString* image = [alert objectForKey:#"image"];
[images_url addObject:image];
}
[self.myTable reloadData];
}
where myTable is my synthesized TableView.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int i=[images_url count]/2;
return i;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier=#"ListTableCell";
//this is the identifier of the custom cell
ListsCell *cell = (ListsCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ListsCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
/*NSString *url_left=[images_url objectAtIndex:(indexPath.row*2)];
NSLog(#"Left url is:%#",url_left);
NSString *url_right=[images_url objectAtIndex:(indexPath.row*2+1)];
NSLog(#"Right url is:%#",url_right);*/ THEY ARE PRINTED HERE
NSURL *url_left=[NSURL URLWithString:[images_url objectAtIndex:(indexPath.row*2)]];
cell.Left.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:url_left]];
NSURL *url_right=[NSURL URLWithString:[images_url objectAtIndex:(indexPath.row*2+1)]];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 81;
}
If I remove the reload data, then I do bot see their values and not the correct number of lines, so it is necessary.
So can anyone find out what is wrong in here?