I'm building an app that retrieves items from a Parse database and inserts them into a UITableView. In my Parse database, each item has its own date (i.e. film dates). Now this is the part I’m having trouble with:
I would like to sort the items by their own date, with the date for that item being in the section header. I would also like to show only the items whose date is from the current date and onwards. Please also know that I’m using the latest version of iOS and using Objective-C. I have exhausted other sources but have yet to find exactly what I need. Any guidance will be greatly appreciated!
Right now I have this in my ShowsTableViewController.m:
My getShows method:
-(void)getShows{
PFQuery *retrieveShows = [PFQuery queryWithClassName:#"shows"];
[retrieveShows findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError
*error) {
//NSLog(#"%#", objects);
if (!error)
{
_showsArray = [[NSArray alloc] initWithArray:objects];
}
[showsTableView reloadData];
}];
}
And this is how I'm currently populating the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ShowsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"showsCell" forIndexPath:indexPath];
PFObject *tempObject = [_showsArray objectAtIndex:indexPath.row];
cell.cellTitle.text = [tempObject objectForKey:#"title];
return cell;
}
With you require, I think you have to sort your data and put it in to a Array. And this Array will hold list of Dictionary. Each Dictionary will have two key (first key is title: and value of it is title you want show to header, second key is data: and value of it is array item in seciton)
And now you will implement UITableViewDataSource for it:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self.listData count];
}
for each section you can implement same like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *data = [[self.listData objectAtIndex:section] objectForKey:#"data"];
}
And show header:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[self.listData objectAtIndex:section] objectForKey:#"title"];
}
And show to cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ShowsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"showsCell" forIndexPath:indexPath];
PFObject *tempObject = [[self.listData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
cell.cellTitle.text = [tempObject objectForKey:#"title];
return cell;
}
You can do this way to achieve what you want.
Related
i'm trying to do a weather application
#import "LocationTableViewController.h"
#interface LocationTableViewController (){
NSArray *hourlyData;
NSArray *dailyData;
}
#end
#implementation LocationTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *str = #"https://api.forecast.io/forecast/cd8edc928426f2ac3e341441c7a9c6d3/37.8267,-122.423";
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:str]];
NSDictionary *dataFromWeb = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
i took a json query that gives hourly and daily data, then converted it into dictionary. Here i created two dictionaries ie hourly dictionary and daily dictionary which contains fields like temperature, humidity, etc etc
My main goal is to create a weather app using both of the dictionaries hourly and daily by loading them into a table view.
NSDictionary *hourlyDict = [dataFromWeb objectForKey:#"hourly"];
hourlyData = [hourlyDict objectForKey:#"data"];
NSDictionary *dailyDict = [dataFromWeb objectForKey:#"daily"];
dailyData = [dailyDict objectForKey:#"data"];
NSLog(#"%#", [[dailyData objectAtIndex:0] objectForKey:#"humidity"]);
}
By here i successfully created both the dictionaries and tried to NSlog the data it works fine.
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
I feel like my problem starts here in loading the dictionary into tableView.
1) In storyboard i embedded the table view into NavigationView.
2) i made the table View content as dynamic protocol
3) named the cell identifier as cell
i think problem starts here in sending data into table. Basically my app should contains 3 sections summary,hourly data and daily data. but i just want to try for now only on daily data.
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
Since i don't want any section, i removed this no.of. sections, but it threw me error, so kept it back and returned 0. , i also tried making it 1, but app crashes.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"hello");
return dailyData.count;
}
Here i want columns as no.of rows in dictionary, so i made dailyData.count.
Here starts the main problem, this - (UITableViewCell *)tableView:........ function is not being called, i tried to NSlog a message, it didn't show up
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
NSLog(#"hello");
cell.textLabel.text = [[dailyData objectAtIndex:indexPath.row]objectForKey:#"sunsetTime"];
return cell;
}
can some one help me out please. Thanks in advance. Im new to programming.
here i attached the Google Drive link for project
To fix your issue you need to set your number of sections to 1 (you must always have at least 1 section for anything to display).
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
The reason you are getting a crash when you set your number of sections to 1 is because you are trying to use an NSDictionary as an NSString. You need to get an NSString from the NSDictionary. The below code will get the summary from the daily data for that row and display the summary.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
NSDictionary *rowData = [dailyData objectAtIndex:indexPath.row];
cell.textLabel.text = [rowData objectForKey:#"summary"];
return cell;
}
// sections should be 1 instead of 0
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
[dailyData objectAtIndex:indexPath.row] has following dictionary that cannot be assigned as Cell label text , you have to assign some string value to Cell Label text
{
apparentTemperatureMax = "60.49";
apparentTemperatureMaxTime = 1462316400;
apparentTemperatureMin = "52.96";
apparentTemperatureMinTime = 1462276800;
cloudCover = "0.92";
dewPoint = "50.37";
humidity = "0.8100000000000001";
icon = "partly-cloudy-day";
moonPhase = "0.89";
ozone = "351.23";
precipIntensity = 0;
precipIntensityMax = 0;
precipProbability = 0;
pressure = "1014.68";
summary = "Mostly cloudy throughout the day.";
sunriseTime = 1462281126;
sunsetTime = 1462331002;
temperatureMax = "60.49";
temperatureMaxTime = 1462316400;
temperatureMin = "52.96";
temperatureMinTime = 1462276800;
time = 1462258800;
visibility = "8.779999999999999";
windBearing = 275;
windSpeed = "5.83";
}
cell.textLabel.text = [dailyData objectAtIndex:indexPath.row]; you are assigning a dictionary to tableViewCell label. if you want specific key value then check below code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
//Number to Sting --> [Number stringValue]
cell.textLabel.text = [[[dailyData objectAtIndex:indexPath.row]objectForKey:#"sunsetTime"] stringValue];
return cell;
}
I was trying to pass float into my table cell text, theres the mistake. We have to pass only text into that one, but i was trying to insert float values. now i passes some text values it works fine
Thank you all for your lovable support. Thank you once again
use this below code, And your code is working for me,
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"hello");
return dailyData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
NSLog(#"hello %#",[[dailyData objectAtIndex:indexPath.row] objectForKey:#"humidity"]);
cell.textLabel.text = [NSString stringWithFormat:#"%#",[[dailyData objectAtIndex:indexPath.row] objectForKey:#"humidity"]];
return cell;
}
And your output is given below,
humidity value is printed
hope its helpful
You must show not to come out the data, because your dailyData is a NSArray! How do you use an array as a string to use?Suggest you use a model, to store data.
NSDictionary *hourlyDict = [dataFromWeb objectForKey:#"hourly"];
hourlyData = [hourlyDict objectForKey:#"data"];
NSDictionary *dailyDict = [dataFromWeb objectForKey:#"daily"];
dailyData = [dailyDict objectForKey:#"data"];
for (id obj in hourlyData) {
newsModel *model=[[newsModel alloc]init ];
model.name=obj[#"summary"];
[_dataArray addObject:model];
}
NSLog(#"%#", [[dailyData objectAtIndex:0] objectForKey:#"humidity"]);
In the table view delegate :
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIde=#"cell";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIde];
if (!cell) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIde ];
}
newsModel *model=_dataArray[indexPath.row];
cell.textLabel.text=model.name;
return cell;
}
I'm working on a project and I want the user to be able to search a list on a UITableView. I've added the search bar and connected it to the search display controller. I have no idea how to actually search the list and grab the data from parse, filter it, set it to the PFUser of toUser, and display it. Anyone know how to do this?
Here's the code where I save the message:
if (toUser!= nil){
app[#"toUser"]=toUser;
}
[app save];
Here are some code snippets for the table view:
This displays the users and filters out the current user:
ParseExampleAppDelegate *delegate=[[UIApplication sharedApplication] delegate];
PFQuery *query = [PFUser query];
users = [[query findObjects] mutableCopy];
for(PFUser *user in users){
if ([user.objectId isEqualToString:delegate.applicationUser.objectId]){
[users removeObject:user];
break;
}
}
[users removeObject:delegate.applicationUser];
NSLog(#"all user: %lu",users.count);
[self.usersTable setDelegate:self];
[self.usersTable setDataSource:self];
[self.usersTable reloadData];
[self.usersTable reloadData];
Some methods for the table view:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"userCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
PFObject *tempObject = [users objectAtIndex:indexPath.row];
cell.text= [tempObject objectForKey:#"username"];
return cell;
NSMutableArray *filteredStrings;
BOOL isFiltered;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"users:%lu",[users count]);
return [users count];
}
Thanks for your help,
armanb21
i use below code to binding tableview cell by "contacts" entity
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context=nil;
id delegate=[[UIApplication sharedApplication]delegate];
if ([delegate performSelector:#selector(managedObjectContext)])
{
context=[delegate managedObjectContext];
}
return context;
}
- (void)viewDidAppear:(BOOL)animated
{
//fetching contact into tableview
NSManagedObjectContext *moc=[self managedObjectContext];
totalFetch=[[NSFetchRequest alloc]initWithEntityName:#"Contacts"];
// 4 - Sort it if you want
totalFetch.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)]];
_contacts=[[moc executeFetchRequest:totalFetch error:nil]mutableCopy];
[self.myTable reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//create and initializetion cell
static NSString *cellIdentifier=#"cell";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
NSManagedObject *contact=[_contacts objectAtIndex:indexPath.row];
//implementing tableViewCells with Contact attribs
[cell.textLabel setText:[NSString stringWithFormat:#"%#",[contact valueForKey:#"name"]]];
[cell.detailTextLabel setText:[contact valueForKey:#"phoneNum"]];
UIImage *image = [UIImage imageWithData:[contact valueForKey:#"photo"]];
[cell.imageView setImage:image];
return cell;
}
now i want to add index and section to mytableview by first letter of "name" field in "contacts" entity, Please put your answers according to my code, thanks
You need to implement the following datasource methods for UITableView:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
The first two are standard and implement the cells that are going to be displayed in the table view.
The third one is the number of sections the table view should be divided up into. For something like this I would use an 'alphabet array' i.e. an array with all the letters of the alphabet in e.g.:
NSMutableArray *alphabetArray = [[NSMutableArray alloc] init];
for (int i = 0; i < 26; i++) {
char letter = 'A';
letter += i;
[alphabetArray addObject:[NSString stringWithFormat:#"%c", letter]];
}
You can return alphabetArray.count for the third datasource method.
The fourth method requests the section number for the section title, all you need to do here is return: [alphabetArray indexOfObject:title];.
The fifth method is asking for the title for a specific section so you can return: alphabetArray[section]; here.
Finally the sixth method is asking for all the titles in an array so you can just return alphabetArray here .
In order to get the number of rows in a section you need to break down your contacts array by starting letter. To do this you can use predicates e.g.
NSString *letter = alphabetArray[indexPath.section];
NSArray *filteredContacts = [contacts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"name BEGINSWITH[cd] %#", letter]];
return filteredContacts.count;
You can apply the same logic to get the contact to display in a cell:
NSString *letter = alphabetArray[indexPath.section];
NSArray *filteredContacts = [contacts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"name BEGINSWITH[cd] %#", letter]];
Contact *contact = filteredContacts[indexPath.row];
Hope this helps.
I use parse.com as backend, and my query was very slow, so I am trying to change it to use blocks.
Basically, my query populates an array with everything I need, and according to if statements, I'm calling methods inside the block, these methods populate the array that I will use in cellForRowAtIndexPath. The problem is that when I try to reloadDatainside block, the app crashes.
Here is the code:
- (void)queryForTable {
PFQuery *exerciciosQuery = [PFQuery queryWithClassName:#"ExerciciosPeso"];
[exerciciosQuery whereKey:#"usuario" equalTo:[PFUser currentUser]];
[exerciciosQuery includeKey:#"exercicio"];
exerciciosQuery.cachePolicy = kPFCachePolicyCacheElseNetwork;
[exerciciosQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
[self configurarDatas];
_seriesArray = objects;
if (_seriesArray.count > 0) {
NSPredicate *predIniciante = [NSPredicate predicateWithFormat:#"serie contains [cd] %#", #"Ini"];
NSArray *arrayIniciante = [_seriesArray filteredArrayUsingPredicate:predIniciante];
NSArray *arrayInicianteApenasSeries = arrayIniciante;
NSArray *arrayInicianteApenasSeries2 = [arrayInicianteApenasSeries valueForKey:#"serie"];
NSSet *setInicianteApenasSeries = [NSSet setWithArray:arrayInicianteApenasSeries2];
NSArray *arrayInicianteCount = [setInicianteApenasSeries allObjects];
if (arrayInicianteCount.count > 0) {
[self popularSeriesInicianteAB];
// [self.tableView reloadData];
}
else if (arrayInicianteCount.count > 8) {
[self popularSeriesInicianteC];
// [self.tableView reloadData];
}
else {
[self popularSeriesAvancado];
// [self.tableView reloadData];
NSLog(#"POPULAR SERIES AVANÇADO");
}
}
}];
}
I have also tried to reloadData using dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; });, but it didn't work as well.
Anyway, I imagine that if I erase my methods and put everything inside the block, it will work, but I don't want to do that, as calling methods using if make my code easier to follow.
UPDATE:
For completeness, here are my DataSource methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"numberOfRowsInSection %li", (unsigned long)_seriesForDisplay.count);
return _seriesForDisplay.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"Cell";
PFTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
PFObject *o = _seriesForDisplay[indexPath.row];
// Texto da célula
cell.textLabel.text = o[#"serieDisplay"];
cell.detailTextLabel.text = o[#"grupos"];
return cell;
}
There are 2 way to implement data in tableview with Parse SDK
PFqueryTableViewController: you need implement
- (PFQuery *)queryForTable {
return query;
}
- (PFObject *)objectAtIndex:(NSIndexPath *)indexPath {
// overridden, since we want to implement sections
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath object:(PFObject *)object {
//get data: object
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForNextPageAtIndexPath:
(NSIndexPath *)indexPath
UITableViewController/ UITableview in UIViewController:
This is normal way, implement uitableview delegate/datasource, you can write a method like (void)queryForTable and call reloadData in here.
I was using PFQueryTableViewController, which is from parse.com backend and has some different methods. I changed my query to void and used findObjectsInBackgroundWithBlock. Therefore, my method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object, was not receiving the PFObjects, that's why I was getting a crash when tried to reloadData.
I changed my table back to UITableViewController.
I'm using dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
}); inside block and it's working now.
Great answers to this post, helped me a lot.
If you can't guarantee what thread a block will be run on (if it can run on a background thread) then you should switch to the main thread before actioning any UI changes. This could be done with performSelectorOnMainThread:withObject:waitUntilDone: or dispatch_async(dispatch_get_main_queue(), ^{.
I started to use IOS and the Graph Api some weeks ago. I have problems to fill a UITableView with the albums data that I retrieve from facebook. I make my appdelegete my uitabledatasource and uitabledelegate too I make the following request after the user is logged:
NSString* fql = [NSString stringWithString:#"select object_id, cover_object_id, name, description from album where can_upload=1 and owner=me ()"];
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObject:fql forKey:#"query"];
[facebook requestWithMethodName:#"fql.query" andParams:params andHttpMethod:#"GET" andDelegate:self];
[theTable reloadData];
And I implement the following to the table:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.resultData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SimpleTableIdentifier] autorelease];
}
NSUInteger row = [indexPath row]; cell.textLabel.text = [[self.resultData objectAtIndex:row] valueForKey:#"name"];
NSLog(#"the name %#", [[self.resultData objectAtIndex:row] valueForKey:#"name"]);
return cell;
}
And a manage the result like this:
- (void)request:(FBRequest *)request didLoad:(id)result {
if ([result isKindOfClass:[NSArray class]]) {
resultData=result;
[theTable reloadData];
}
NSLog(#"Result of API call: %#", result);
}
I get a correct result of the query but the table never reload the data so it is always empty
First of all, you need to retain resultData in request:didLoad: (use the setter method!).
Secondly, you should check if the table does not try reload the data at all or if something in your table view data source methods goes wrong. If the former, it is likely that theTable is actually nil in request:didLoad: so that the reloadData call has no effect. Check that with the debugger.
If that's not the case, we need more information. Go through the code with the debugger and check for each of the table view data source methods if they get called and where in that flow the processing goes wrong.