How to pass a value from NSMutableArray to a PFUser object? - ios

I have a mutable array, called mainArray. It contains a username that is the search result of a user search. I'm displaying every search result in a custom table view cell, that also have a UIButton called addButton. I would like to add the user to the friends list of the current user, when the current user taps the addButton.
The problem is that i can not assign the value from "mainArray" to the "newUser". I've tried some solutions, but the result was always an error or freeze, therefore it would be amazing, if somebody could help me to solve this problem.
My last try wast this line: (it makes this warning: Incompatible pointer types sending NSIndexPath * to parameter of type NSString)
[newUser addUniqueObjectsFromArray:mainArray forKey:indexPath];
.m file:
- (void)viewDidLoad
{
[super viewDidLoad];
mainArray = [[NSMutableArray alloc] initWithObjects:#"User", nil];
self.currentUser = [PFUser currentUser];
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [mainArray count];
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DevTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"thisCell"];
cell.usernameLabel.text = [mainArray objectAtIndex:indexPath.row];
[cell.addButton addTarget:self action:#selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
- (void)didTapButton:(id)sender {
UIButton *button = (UIButton *)sender;
CGPoint pointInSuperview = [button.superview convertPoint:button.center toView:tableView];
NSIndexPath *indexPath = [tableView indexPathForRowAtPoint:pointInSuperview];
PFUser *newUser = [PFUser user];
// The problem is here.
[newUser addUniqueObjectsFromArray:mainArray forKey:indexPath];
PFRelation *friendsRelation = [self.currentUser relationForKey:#"friendsRelation"];
if ([self isFriend:newUser]) {
for (PFUser *friend in self.friends) {
if ([friend.objectId isEqualToString:newUser.objectId]){
NSLog(#"some log");
break;
}
}
}
else {
[self.friends addObject:newUser];
[friendsRelation addObject:newUser];
}
[self.currentUser saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error){
NSLog(#"Error %# %#", error, [error userInfo]);
}
}];
}
-(BOOL)isFriend:(PFUser *)newUser {
for (PFUser *friend in self.friends) {
if ([friend.objectId isEqualToString:newUser.objectId]){
return YES;
}
}
return NO;
}

[newUser addUniqueObjectsFromArray:mainArray forKey:indexPath];
You passing NSIndexPathwhere it should be an NSString. You need to convert your indexPath into a string.
So maybe something like this if you want both the section and row to be the key:
NSString *newUserKey = [NSString stringWithFormat:#"%d-%d", indexPath.section, indexPath.row];
[newUser addUniqueObjectsFromArray:mainArray forKey:newUserKey];
EDIT:
You don't have to pass in an array of PFObjects, here is the example from Parse docs:
[gameScore addUniqueObjectsFromArray:#[#"flying", #"kungfu"] forKey:#"skills"];
As you can see they are passing in an array of strings just as you are. I would check to see that your mainArray isn't nil. I've tested this and it works so you are doing something else wrong other than passing in an array of strings.

Related

UISwitch changing object parse objective c

I am working on a app that you can change when a item on the menu is in stock or out of stock.
I have it now so it changes the UISwitch to on or off when it loads the screen. I need each switch to change a NSString in parse that makes it one or zero.One meaning that it is on zero meaning its off.
I am fairly new to objective c and parse so if any one could help me get a start on this problem that would be great!
You might use something like that:
PFQuery *query = [PFQuery queryWithClassName:#"YourClass"];
[query whereKey:#"user" equalTo:[PFUser currentUser]];
[query getFirstObjectInBackgroundWithBlock:^(PFObject * yourClass, NSError *error) {
if (!error) {
// Found yourClass object
[yourClass setObject:isInStock forKey:#"isInStock"];
// Save
[yourClass saveInBackground];
} else {
// Did not find any yourClass object for the current user
NSLog(#"Error: %#", error);
}
}];
NSArray *listObjects = .... (loading from Server) // List of PFObject
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
PFObject *object = [listObjects objectAtIndex:indexPath.row];
YourCell *cell = .....
if ([[object valueForKey:#"sandwichesOutofstock"] intValue] == 1)
cell.switch.on = true;
else
cell.switch.on = false;
cell.switch.tag = 500 + index.row;
[cell.switch addTarget:self action:#selector(switchTouch:) forControlEvents:UIControlEventTouchUpInside]
.........
}
(IBAction)switchTouch:(UISwitch *)switch{
long index = switch.tag - 500;
PFObject *object = [listObjects objectAtIndex:index];
if(switch.on)
[object setValue:#"1" ForKey:#"sandwichesOutofstock"];
else{
[object setValue:#"0" ForKey:#"sandwichesOutofstock"];
}
[object saveInBackground];
[self.tableView reloadRowsAtIndexPaths:[NSIndexPath indexPathForRow:index inSection:0] withRowAnimation:UITableViewRowAnimationNone];
}
You could assign a reference of the PFObject to the cell. Then when the switch changes just get the cell's object and make the change.

PFRelation Deleting One Object From A PFRelation, Not All

Explanation of what's taking place: The user has added a job as their favorite within another view. Now the user is in the Favorites tab and decides that they no longer want the job as one of their favorites anymore, so they swipe to delete the job. They tap the delete button and the errors below take place...the code works as is, but it also deletes every single job the user has saved as a favorite, instead of just deleting the one job.
My code also gives me an alert of:
Warning: A long-running operation is being executed on the main thread.
Break on warnBlockingOperationOnMainThread() to debug.
#import "JobDetailViewController.h"
#import "MyFavoritesTableViewController.h"
#import "Parse/Parse.h"
#import "Job.h"
#import "JobListViewController.h"
#interface MyFavoritesTableViewController ()
#property (nonatomic, strong) NSString *mainTitle;
#property (nonatomic, strong) NSString *subTitle;
#end
#interface MyFavoritesTableViewController ()
#end
#implementation MyFavoritesTableViewController
{}
#synthesize mainTitle;
#synthesize subTitle;
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if ([PFUser currentUser]) {
// Custom the table
// The className to query on
self.parseClassName = #"Jobs";
// The key of the PFObject to display in the label of the default cell style
self.textKey = #"Position";
// Whether the built-in pull-to-refresh is enabled
self.pullToRefreshEnabled = YES;
// Whether the built-in pagination is enabled
self.paginationEnabled = YES;
// The number of objects to show per page
self.objectsPerPage = 30;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)objectsWillLoad {
[super objectsWillLoad];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.tableView reloadData];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object: (PFObject *)object
{
static NSString *myJobsTableIdentifier = #"myFavsCell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:myJobsTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:myJobsTableIdentifier];
}
// Configure the cell
PFFile *thumbnail = [object objectForKey:#"imageFile"];
PFImageView *thumbnailImageView = (PFImageView*)[cell viewWithTag:100];
thumbnailImageView.image = [UIImage imageNamed:#"AppIcon.png"];
thumbnailImageView.file = thumbnail;
[thumbnailImageView loadInBackground];
UILabel *positionLabel = (UILabel*) [cell viewWithTag:101];
positionLabel.text = [object objectForKey:#"Position"];
UILabel *rotationLabel = (UILabel*) [cell viewWithTag:102];
rotationLabel.text = [object objectForKey:#"Rotation"];
UILabel *locationLabel = (UILabel*) [cell viewWithTag:103];
locationLabel.text = [object objectForKey:#"Location"];
UILabel *typeLabel = (UILabel*) [cell viewWithTag:104];
typeLabel.text = [object objectForKey:#"Type"];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showDetailedView"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
Job *job = [[Job alloc] init];
JobDetailViewController *destViewController = segue.destinationViewController;
PFObject *object = [self.objects objectAtIndex:indexPath.row];
job.position = [object objectForKey:#"Position"];
job.poc = [object objectForKey:#"POC"];
job.email = [object objectForKey:#"Email"];
job.phone = [object objectForKey:#"Phone"];
job.apply = [object objectForKey:#"Apply"];
job.imageFile = [object objectForKey:#"imageFile"];
job.rotation = [object objectForKey:#"Rotation"];
job.location = [object objectForKey:#"Location"];
job.type = [object objectForKey:#"Type"];
job.clearance = [object objectForKey:#"Clearance"];
job.job_description = [object objectForKey:#"Job_Description"];
job.qualifications = [object objectForKey:#"Qualifications"];
job.originalJob = object;
destViewController.job = job;
}
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([self.objects count] == indexPath.row) {
[self loadNextPage];
} else {
PFObject *photo = [self.objects objectAtIndex:indexPath.row];
NSLog(#"%#", photo);
// Do something you want after selected the cell
}
}
- (PFQuery *)queryForTable
{
PFUser *user = [PFUser currentUser];
PFRelation *relation = [user relationForKey:#"Favorites"];
PFQuery *myquery = [relation query];
if (self.pullToRefreshEnabled) {
myquery.cachePolicy = kPFCachePolicyNetworkOnly;
}
return myquery;
}
#pragma mark - DeleteJobViewDelegate
- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
PFUser *user = [PFUser currentUser];
PFRelation *relation = [user relationForKey:#"Favorites"];
PFQuery *myquery = [relation query];
NSArray *array = [myquery findObjects];
for (PFObject *object in array)
{
[relation removeObject:object];
}
[user saveInBackground];
[self.tableView reloadData];
[self loadObjects];
}
#end
The problem is that you are removing all the objects from the Relation:
NSArray *array = [myquery findObjects];
for (PFObject *object in array)
{
[relation removeObject:object];
}
What your code is doing is going though your array and removing each object from the relation.
What you want to do is to delete the job for that cell only. You can get that using the indexPath:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
PFUser *user = [PFUser currentUser];
PFRelation *relation = [user relationForKey:#"Favorites"];
[relation removeObject:[self.objects objectAtIndex:indexPath.row]];
[user saveInBackground];
[self.tableView reloadData];
[self loadObjects];
}
Your second problem:
Warning: A long-running operation is being executed on the main thread. Break on warnBlockingOperationOnMainThread() to debug.
That warning is because findObjects is a synchronous call. You should use the findObjectsInBackground instead. But if you make the changes I gave above, you won't need it.

I'm getting this error when I try to delete a row

I'm getting this error when I try to delete a row. Please who can help me!!!!
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 3. The number of rows contained in an existing section after the update (3) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
//
// InboxTableViewController.m
// Ribbit
//
// Created by OnMac on 24/11/14.
// Copyright (c) 2014 OnMac. All rights reserved.
//
#import "InboxTableViewController.h"
#import "ImageViewController.h"
#interface InboxTableViewController ()
#end
#implementation InboxTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.recipient = [NSMutableArray arrayWithArray:[self.selectedMessage objectForKey:#"recipientIds"]];
NSLog(#"Delete: %#", self.selectedMessage);
self.moviePlayer = [[MPMoviePlayerController alloc] init];
PFUser *currentUser = [PFUser currentUser];
if (currentUser) {
NSLog(#"Currrent user: %#", currentUser.username);
}
else {
[self performSegueWithIdentifier:#"showLogin" sender:self];
}
}
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
PFUser *currentUser = [PFUser currentUser];
if (currentUser) {
PFQuery *query = [PFQuery queryWithClassName:#"Message"];
[query whereKey:#"recipiendID" equalTo:[[PFUser currentUser] objectId]];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
else{
// We found messages!!!
self.messages = objects;
[self.tableView reloadData];
// NSLog(#"messages: %#", self.messages);
}
}];
}
else {
[self performSegueWithIdentifier:#"showLogin" sender:self];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#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.messages count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
// Configure the cell...
PFObject *message = [self.messages objectAtIndex:indexPath.row];
cell.textLabel.text = [message objectForKey:#"Username"];
// NSLog(#"ALT: %#", message);
NSString *fileType = [message objectForKey:#"fileType"];
if ([fileType isEqualToString:#"image"]) {
PFFile *im = [message objectForKey:#"file"];
NSData *resumeData = [im getData];
cell.imageView.image = [UIImage imageWithData:resumeData];
}
else{
cell.imageView.image = nil;
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedMessage = [self.messages objectAtIndex:indexPath.row];
NSString *fileType = [self.selectedMessage objectForKey:#"fileType"];
if ([fileType isEqualToString:#"image"]) {
[self performSegueWithIdentifier:#"showImage" sender:self];
}
else{
// File type is video
PFFile *videoFile = [self.selectedMessage objectForKey:#"file"];
NSURL *fileUrl = [NSURL URLWithString:videoFile.url];
self.moviePlayer.contentURL = fileUrl;
[self.moviePlayer prepareToPlay];
// Add it to the view controller so we can see it
[self.view addSubview:self.moviePlayer.view];
[self.moviePlayer setFullscreen:YES animated:YES];
}
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
PFObject *message1 = [self.messages objectAtIndex:indexPath.row];
[message1 deleteInBackground];
if (editingStyle == UITableViewCellEditingStyleDelete) {
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
[self.tableView reloadData];
}
- (IBAction)logout:(id)sender {
[PFUser logOut];
[self performSegueWithIdentifier:#"showLogin" sender:self];
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"showLogin"]) {
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
}
else if ([segue.identifier isEqualToString:#"showImage"]) {
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
ImageViewController *imageViewController = (ImageViewController *)segue.destinationViewController;
imageViewController.message = self.selectedMessage;
}
}
#end
First, please edit your code more. You have more white space than actual code, and pasting that much white space just makes the process longer.
Second, try reading the error message. It's saying that you are deleting a row from the datasource when you aren't removing it from the table. What I suspect is happening is inside your commitEditingStyle method:
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
PFObject *message1 = [self.messages objectAtIndex:indexPath.row];
[message1 deleteInBackground];
if (editingStyle == UITableViewCellEditingStyleDelete) {
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
[self.tableView reloadData];
}
Look at what you're doing. There's a lot of issues here. First, you're deleting a message 100% of the time this method is called. That means you're always modifying your datasource. But look at your if statement - this means that you are not always deleting a row. Now you sometimes delete a message without deleting the row from the table. This WILL cause the crash.
Second - from what it sounds like, it sounds like you're deleting the message in the background. This is potentially a very bad thing. Why? Because if you're waiting on a delegate callback in an asynchronous fashion, then this will lead to very bad race conditions.
Your code should look like this:
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
PFObject *message1 = [self.messages objectAtIndex:indexPath.row];
[self.messages removeObject:message1];
[message1 deleteInBackground];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
}
Note that I added [self.messages removeObject:message1] to make your dataSource consistent with the table immediately. I don't know what you were doing in [PFObject deleteInBackground], but if you weren't immediately removing the message object from your dataSource, then you can run into bad issues.

UITableViewController [__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array' with PFTask thenCallBackOnMainThreadAsync:]

I am purposely creating a empty Array to not display anything on the UITablewView.
However, it gives me that error.
To debug, I even created an empty UITableViewController and refer storyboard file to this. However, it is giving me the same error.
I just tried and connect it with an empty UIViewController, it is giving me the same objectAtIndex error.
So I doubt it is the problem with the what I am indexing for cells.
When I run, the screen is shown but it throws the error and it freezes.
The declaration of the newsList is:
#property (strong, nonatomic)NSArray *newsList
This is what I have for the UITableViewController.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.currentUser = appDelegate.currentUser;
NSString *addNewsFeed = #"_NewsFeed";
if (self.currentUser)
{
if (appDelegate.selectedGroup == nil)
{
self.newsList = nil;
}
else
{
NSLog(#"SELECTED GROUP EXIST");
NSString *currentNewsFeed = [appDelegate.selectedGroup[#"name"] stringByAppendingString:addNewsFeed];
PFQuery *query = [PFQuery queryWithClassName:currentNewsFeed];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error)
{
NSLog(#"Error: %#, %#", error, [error userInfo]);
}
else
{
self.newsList = objects;
[self.tableView reloadData];
}
}];
}
}
else
{
NSLog(#"%#", appDelegate.currentUser);
[self performSegueWithIdentifier:#"loginView" sender:self];
}
NSLog(#"ZXCVZCVZ: %#", self.newsList);
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (appDelegate.selectedGroup == nil)
{
NSLog(#"NO CELL HERE");
return 0;
}
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (appDelegate.selectedGroup == nil)
{
NSLog(#"NO CELL");
return 0;
}
return [self.newsList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"NO LIST FOUND");
static NSString *CellIdentifier = #"News";
NSLog(#"DSFSDFSDFSFS");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PFObject *item = [self.newsList objectAtIndex:indexPath.row];
cell.textLabel.text = item[#"title"];
cell.detailTextLabel.text = item[#"news"];
return cell;
}
you need to allocate the memory for array as below
self.newsList=[[NSMutableArray alloc]init];//At viewWIllAppear
Without alloc the self.newsList you cannot able to store any records in it...
Hope it fixes...

Search bar is working AFTER "Cancel Button"

I've made a view for editing friend, with a searchbar. My adding/deleting friends is working fine, but I've a problem with my adding/deleting friends WITH SEARCHBAR...
My searchbar finds well the email I'm tapping, but the order change :
if I find 2 email with my searchbar, the 2 email will are the 2 first email in my property "Allfriend", and not the email I found with searchbar...
Is there any code to complete in didSelectRowAtIndexPath after NSLog ?
I let you see my code, tell me if you see a problem :
editfriend.h :
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#interface EditFriendsViewController : UITableViewController <UISearchBarDelegate, UISearchDisplayDelegate>
#property (nonatomic, strong) NSArray *allUsers;
#property (nonatomic, strong) PFUser *currentUser;
#property (nonatomic, strong) NSMutableArray *friends;
#property (strong, nonatomic) NSArray *searchResults;
#property (nonatomic, strong) PFUser *user;
#property (nonatomic, strong) NSMutableArray *filteredArray;
#property (nonatomic, strong) UIImage *MindleNav;
-(BOOL)isFriend:(PFUser*)user;
#end
editfriend.m :
#import "EditFriendsViewController.h"
#interface EditFriendsViewController ()
#end
#implementation EditFriendsViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.titleView = [[UIImageView alloc] initWithImage:self.MindleNav];
self.searchResults = [[NSArray alloc] init];
PFQuery *query = [PFUser query];
[query orderByAscending:#"email"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
else {
self.allUsers = objects;
// self.user = [objects objectAtIndex:0];
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
}
}];
self.currentUser = [PFUser currentUser];
}
#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.
if (tableView == self.searchDisplayController.searchResultsTableView)
{
return [self.searchResults count];
}
else
{
return [self.allUsers count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PFUser *user = [self.allUsers objectAtIndex:indexPath.row];
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [[self.searchResults objectAtIndex:indexPath.row] email];
} else {
cell.textLabel.text = user.email;
}
if ([self isFriend:user]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
PFRelation *friendsRelation = [self.currentUser relationforKey:#"friendsRelation"];
//Edit Friends with searchbar
if (tableView == self.searchDisplayController.searchResultsTableView) {
PFUser *user = [self.searchResults objectAtIndex:indexPath.row];
if ([self isFriend:user]) {
cell.accessoryType = UITableViewCellAccessoryNone;
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
for(PFUser *friend in self.searchResults) {
if ([friend.objectId isEqualToString:user.objectId]) {
[self.friends removeObject:friend];
break;
}
}
[friendsRelation removeObject:user];
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.friends addObject:user];
[friendsRelation addObject:user];
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
}
[self.currentUser saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
//Edit Friends
} else {
PFUser *user = [self.allUsers objectAtIndex:indexPath.row];
if ([self isFriend:user]) {
cell.accessoryType = UITableViewCellAccessoryNone;
for(PFUser *friend in self.friends) {
if ([friend.objectId isEqualToString:user.objectId]) {
[self.friends removeObject:friend];
break;
}
}
[friendsRelation removeObject:user];
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.friends addObject:user];
[friendsRelation addObject:user];
}
[self.currentUser saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
}
#pragma mark - Helper methods
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"email beginswith[c] %#", searchText];
self.searchResults = [self.allUsers filteredArrayUsingPredicate:predicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
- (BOOL)isFriend:(PFUser *)user {
for(PFUser *friend in self.friends) {
if ([friend.objectId isEqualToString:user.objectId]) {
return YES;
}
}
return NO;
}
#end
You're calling [self.tableView reloadData] on a background thread (due to findObjectsInBackground), so your UI won't update right away.
If you want the changes to take place instantly, you need to rewrite that line to:
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
Also, since you already do a query for all objects in viewDidLoad, when the user would like to search, you shouldn't query again, but instead have a property called filteredUsers, which holds the user you'd like to display.
You can filter an array with:
self.filteredArray = [self.allUsers filteredArrayUsingPredicate:predicate];
You can take a look here on how to create an NSPredicate.

Resources