I am attempting to work a segmented control to display data from a search into categories. However although data is received it is not being displayed on my table. Here is my code for the two View Controllers. The child View controller is the one in which the UITableView is stored.
PARENT VC
- (void)searchPeople:(NSString*)text {
if(![text isEqualToString:#""]){
PFQuery *userWithName = [PFQuery queryWithClassName:#"_User"];
[userWithName whereKey:#"fullName" containsString:text];
PFQuery *userWithHandle = [PFQuery queryWithClassName:#"_User"];
[userWithHandle whereKey:#"username" containsString:text];
PFQuery *userQuery = [PFQuery orQueryWithSubqueries:#[userWithHandle,userWithName]];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {
NSLog(#"USERS: %#",results);
[self.userResults removeAllObjects];
[self.userResults addObjectsFromArray:results];
[[ArrayManager sharedInstance].searchResults addObjectsFromArray:results];
NSLog(#"Count Number: %#", [ArrayManager sharedInstance].searchResults);
[[NSNotificationCenter defaultCenter] postNotificationName:#"reload_data" object:self];
}];
}
}
CHILD VC
-(void)handle_data {
[self.tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Object Entries: %lu", (unsigned long)[[ArrayManager sharedInstance].searchResults count]);
NSMutableArray * array = [[ArrayManager sharedInstance] getGlobalArray];
return [array count];
}
- (void)tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *data = [[ArrayManager sharedInstance]init].searchResults[indexPath.row];
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier];
}
cell.textLabel.text = data[#"objectId"];
return cell;
}
Data is returned fine from the server however, there is no data being displayed on the table. The ArrayManager class is a Singleton class.
Create a Data Access Object (DAO) and store all information in an array in that.
http://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm
Have both VC's change and access the DAO instead of each other. It is much simpler that way.
Related
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 created UITableView inside UIView (UserListVC) to display user data stored in a column typed array on Parse.com. The column called "followers" contains the array of PFUser objectId who did like the user in a row (in this case is current user).
In userListVC.m:
#implementation UserListViewController
{
NSMutableArray *tableData;
}
- (void)viewDidLoad {
[super viewDidLoad];
/*
tableData = [NSMutableArray arrayWithObjects:#"user1", #"user2", nil];
NSLog(#"tableData --> %#", tableData);
*/
tableData = [[NSMutableArray alloc] init];
PFQuery *userQuery = [PFQuery queryWithClassName:kPAWParseUserClassKey];
[userQuery whereKey:kPAWParseUsernameKey equalTo:[PFUser currentUser].username];
userQuery.cachePolicy = kPFCachePolicyNetworkElseCache;
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error)
{
if( !error )
{
NSArray *array = [users valueForKey:#"followings"];
for (int i = 0; i <= array.count; i++)
PFQuery *followingsQuery = [PFUser query];
[followingsQuery whereKey:#"objectId" equalTo:[[[users valueForKey:#"followings"] objectAtIndex:0] objectAtIndex:i]];
followingsQuery.cachePolicy = kPFCachePolicyNetworkElseCache;
[followingsQuery findObjectsInBackgroundWithBlock:^(NSArray *followings, NSError *error) {
if (!error) {
NSLog(#"following names --> %#", [followings valueForKey:kPAWParseUsernameKey]);
[tableData addObject:[followings valueForKey:kPAWParseUsernameKey]]; //??
[self.tableView reloadData];
NSLog(#"table data --> %#", tableData);
}
}];
}
}];
}
I am now able to extract usernames from the user class by using data array that I get from "followers" column and I also have [self.tableView reloadData]; in async query block but there is still a problem with tableview not showing usernames obtained from tableData. If I use sample data ("user1","user2") just for testing, there is no problem.
Here below I show my log from the code:
2014-12-31 11:05:00.626 Test[12354:60b] following names --> (
user1name
)
2014-12-31 11:05:00.628 Test[12354:60b] table data --> (
(
user1name
)
)
2014-12-31 11:05:00.631 Test[12354:60b] following names --> (
user2name
)
2014-12-31 11:05:00.633 Test[12354:60b] table data --> (
(
user1name
),
(
user2name
)
)
I think it is better to also provide code for the method (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath and here it is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *tableIdentifier = #"TableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:tableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:tableIdentifier];
}
NSLog(#"table data xxxxx --> %#", tableData);
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
The above method NEVER runs but if I test with my sample data, it does run. To be more specific, my questions would be:
This is UIView with UITableView inside it. I am not sure how to do [self.tableView reloadData]; properly. I mean how to declare tableView. In this case I do this:
#interface UserListViewController ()
#property (weak, nonatomic) UITableView *tableView;//????
#end
Why the method (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath never get run?
Just to answer these 2 specific questions:
Connect tableView to IBOutlet in .h file and synthesise it in .m file, then:
[self.tableView reloadData];
do the above inside async block.
The method (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath will get run if do as the above suggests.
However there remains other issues but they are out of the scope of this question I believe.
I have a problem with my TableViewController. There is a custom cell, with a class, and various infos dynamically loaded. My TableViewController appears, but my cell doesn't display, but i can touch this, and my transition with infos are good.
Thanks for your answers.
TableViewController.m
#interface Chat() {
NSMutableArray *messages;
UIRefreshControl *refreshControl;
}
#property (strong, nonatomic) IBOutlet UITableView *tableMessages;
#end
#implementation Chat
NSString *cellIdentifier = #"ChatCell";
- (void)viewDidLoad {
[super viewDidLoad];
[_tableMessages registerClass:[ChatCell class] forCellReuseIdentifier:cellIdentifier];
refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(loadMessages) forControlEvents:UIControlEventValueChanged];
[_tableMessages addSubview:refreshControl];
messages = [[NSMutableArray alloc] init];
[self loadMessages];
}
- (void)loadMessages {
if ([PFUser currentUser] != nil)
{
PFQuery *query = [PFQuery queryWithClassName:PF_MESSAGES_CLASS_NAME];
[query whereKey:PF_MESSAGES_USER equalTo:[PFUser currentUser]];
[query includeKey:PF_MESSAGES_LASTUSER];
[query orderByDescending:PF_MESSAGES_UPDATEDACTION];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error == nil) {
[messages removeAllObjects];
[messages addObjectsFromArray:objects];
[_tableMessages reloadData];
} else [ProgressHUD showError:#"Network error."];
[refreshControl endRefreshing];
}];
}
}
- (void)actionCleanup {
[messages removeAllObjects];
[_tableMessages reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [messages count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ChatCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
[cell bindData:messages[indexPath.row]];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
DeleteMessageItem(messages[indexPath.row]);
[messages removeObjectAtIndex:indexPath.row];
[_tableMessages deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
PFObject *message = messages[indexPath.row];
ChatView *chatView = [[ChatView alloc] initWith:message[PF_MESSAGES_ROOMID]];
[self.navigationController pushViewController:chatView animated:YES];
}
#end
TableViewCell.m
#interface ChatCell() {
PFObject *message;
}
#end
#implementation ChatCell
- (void)bindData:(PFObject *)message_ {
message = message_;
_chatImg.layer.cornerRadius = _chatImg.frame.size.width/2;
_chatImg.layer.masksToBounds = YES;
PFUser *lastUser = message[PF_MESSAGES_LASTUSER];
[_chatImg setFile:lastUser[PF_USER_PICTURE]];
[_chatImg loadInBackground];
_chatUsername.text = message[PF_MESSAGES_DESCRIPTION];
_chatMessage.text = message[PF_MESSAGES_LASTMESSAGE];
NSTimeInterval seconds = [[NSDate date] timeIntervalSinceDate:message.updatedAt];
_chatDate.text = TimeElapsed(seconds);
}
#end
It's because you register the cell using - registerClass:forCellReuseIdentifier:.
If you register it this way you have to construct the view programmatically or load the nib file in ChatCell code.
To solve the problem, do either of these:
Create a nib file containing the view for your table view cell and set the class to ChatCell. Then use - registerNib:forCellReuseIdentifier: to register the nib.
Construct the view programmatically eg. create a UILabel and add it as a subview of ChatCell.
Make the prototype cell in the storyboard and set the cell identifier to ChatCell. Then remove the - registerClass:forCellReuseIdentifier:
Check You are given correct cell Identifier in storyboard. (case sensitive) " ChatCell"
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"ChatCell";
ChatCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
[cell bindData:messages[indexPath.row]];
return cell;
}
You are updating the UI on background thread. Try this, in your "loadMessages" method.
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
//update UI here
if (error == nil) {
[messages removeAllObjects];
[messages addObjectsFromArray:objects];
[_tableMessages reloadData];
} else [ProgressHUD showError:#"Network error."];
[refreshControl endRefreshing];
});
}];
I'm new to objective-C and I am having an issue populating my UItableview with data I retrieved from Parse.
Here is my query:
- (void)viewDidLoad {
[super viewDidLoad];
PFQuery *query = [PFUser query];
[query orderByAscending:#"username"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
} else {
//this is my users array
self.allUsers = objects;
[self.tableView reloadData];
}
}];
I have logged this and can see that I successfully retrieved the data. But when I try to populate my tableView as follows. No data shows up. What am I doing wrong?
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.allUsers count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
PFUser *user = [self.allUsers objectAtIndex:indexPath.row];
cell.textLabel.text = user.username;
return cell;
}
Thanks in Advance for any help.
You need to implement:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView.
I have this code:
for (NSIndexPath *indexPath in tableView.indexPathsForSelectedRows) {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
I have a search bar that filters out search objects and puts a check mark on the cell when you click it. However, if you search and click on the first cell, it checks it off. But if you delete the search text, the check mark shows up on the first cell, not the one that I checked off. Here is a video showing this:
https://docs.google.com/file/d/0B1Of4oDADQCQZkF0aGdhdmF0VjA/edit
Where do I put the code above in the code below so that the checkmark stays with the selected cell?
#import "MSAddFriendsViewController.h"
#interface MSAddFriendsViewController ()
#end
#implementation MSAddFriendsViewController
- (void)viewDidLoad
{
[super viewDidLoad];
PFQuery *query = [PFUser query];
[query orderByAscending:#"username"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error %#, %#", error, [error userInfo]);
}
else {
self.allUsers = objects;
[self.tableView reloadData];
}
}];
self.currentUser = [PFUser currentUser];
self.searchUsers.delegate = self;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchText.length == 0) {
self.userResults = nil;
[self.tableView reloadData];
return ;
}
self.userResults = [NSMutableArray array];
for (PFUser *user in self.allUsers) {
if ([user.username rangeOfString:searchText
options:(NSAnchoredSearch | NSCaseInsensitiveSearch)].location == 0) {
[self.userResults addObject:user];
}
}
[self.tableView reloadData];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
if (self.userResults != nil) {
return [self.userResults count];
}
// Return the number of rows in the section.
return [self.allUsers count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PFUser *user;
if (self.userResults != nil) {
user = [self.userResults objectAtIndex:indexPath.row];
} else {
user = [self.allUsers objectAtIndex:indexPath.row];
}
cell.textLabel.text = user.username;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
PFRelation *friendsRelation = [self.currentUser relationforKey:#"friendsRelation"];
PFUser *user = [self.allUsers objectAtIndex:indexPath.row];
[friendsRelation addObject:user];
[self.currentUser saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
NSLog(#"Error %# %#", error, [error userInfo]);
} }];
}
#end
Can someone please correct the code above?
The first block of code just deselects all of the selected rows. This isn't the solution to your problem. There are a few fundamental issues with your code in general that need correcting...
First off -- you need to keep an array of the selected cells, indexed as the full (non-searching) table is indexed. For example, if there's text in the search bar and the first row is selected, your selected cell array should also indicate the selection boolean of the preceding and following rows not currently visible, and do so all in order.
Secondly -- you need to explicitly set the checkmarks in your cells' accessory views during your cellForRowAtIndexPath: method in order to indicate your selected cells. The only reason that you have a checkmark in the first cell after the search bar is cleared and the table's reloaded is because the cell's being reused (i.e. [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]).
By fixing these first and second issues, you should be off to a good start... When you're not searching, the selected cell array should contain the appropriate selection booleans for all the cells in proper order; and when you are searching, you have to filter the selected cell array in just the same way you'd filter your table based on the search text. And instead of adding checkmarks during didSelectRowAtIndexPath:, you would be better off just indicating that the cell is selected in the selected cell array then reloading table to display the appropriate checkmark.