I have a jobs app that enables users to view jobs. Jobs is a class in my Parse backend. I want to create a Favorites tab where user can mark certain jobs.
I've created a Relations Column in my User Class referring it to my Jobs class.
However, I have ran into this when the user taps to make the job a favorite: [Error]: can't add a non-pointer to a relation (Code: 111, Version: 1.7.5)
I feel like my PFRelation coding is spot on. I've researched this error but cannot seem to find any subject that relates to my problem. I must be making a mistake somewhere but
@interface JobDetailViewController ()
@end
@implementation JobDetailViewController
@synthesize jobPhoto;
@synthesize RotationLabel;
@synthesize QualificationsTextView;
@synthesize Job_DescriptionTextView;
@synthesize TypeLabel;
@synthesize LocationLabel;
@synthesize ClearanceLabel;
@synthesize PositionLabel;
@synthesize job;
@synthesize POC;
@synthesize Email;
@synthesize Phone;
@synthesize Apply;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[_Scroller setScrollEnabled:YES];
[_Scroller setContentSize:CGSizeMake(320, 2200)];
[self dismissKeyboard];
self.PositionLabel.text = job.position;
self.RotationLabel.text = job.rotation;
self.LocationLabel.text = job.location;
self.TypeLabel.text = job.type;
self.ClearanceLabel.text = job.clearance;
jobPhoto.file = (PFFile *)job.imageFile;
[jobPhoto loadInBackground];
NSMutableString *pocText = [NSMutableString string];
for (NSString* poc in job.poc) {
[pocText appendFormat:@"%@\n", poc];
}
self.POC.text = pocText;
NSMutableString *emailText = [NSMutableString string];
for (NSString* email in job.email) {
[emailText appendFormat:@"%@\n", email];
}
self.Email.text = emailText;
NSMutableString *phoneText = [NSMutableString string];
for (NSString* phone in job.phone) {
[phoneText appendFormat:@"%@\n", phone];
}
self.Phone.text = phoneText;
NSMutableString *applyText = [NSMutableString string];
for (NSString* apply in job.apply) {
[applyText appendFormat:@"%@\n", apply];
}
self.Apply.text = applyText;
NSMutableString *qualificationsText = [NSMutableString string];
for (NSString* qualifications in job.qualifications) {
[qualificationsText appendFormat:@"%@\n", qualifications];
}
self.QualificationsTextView.text = qualificationsText;
NSMutableString *job_descriptionText = [NSMutableString string];
for (NSString* job_description in job.job_description) {
[job_descriptionText appendFormat:@"%@\n", job_description];
}
self.Job_DescriptionTextView.text = job_descriptionText;
}
- (IBAction)favoriteButtonAction:(id)sender {
PFObject *jobs = [PFObject objectWithClassName:@"Jobs"];
PFUser *user = [PFUser currentUser];
PFRelation *relation = [user relationForKey:@"Favorites"];
[relation addObject:jobs];
[user saveInBackground];
}
- (void)viewDidUnload
{
[self setJobPhoto:nil];
[self setPositionLabel:nil];
[self setRotationLabel:nil];
[self setLocationLabel:nil];
[self setTypeLabel:nil];
[self setQualificationsTextView:nil];
[self setJob_DescriptionTextView:nil];
[self setPOC: nil];
[self setPhone:nil];
[self setEmail:nil];
[self setApply:nil];
[self dismissKeyboard];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
-(void) dismissKeyboard {
[Email resignFirstResponder];
[POC resignFirstResponder];
[Phone resignFirstResponder];
[Job_DescriptionTextView resignFirstResponder];
[QualificationsTextView resignFirstResponder];
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
return NO;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void) favoriteSuccess {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Success!" message:@"Added job to Favorites!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
}
- (void) favoriteFailed {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Ooooops!" message:@"Error occurred while adding to Favorites!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
}
@end
JobListViewController that populates the jobs prior to the JobDetailViewController:
#import "JobDetailViewController.h"
#import "JobListViewController.h"
#import "Job.h"
#import "SearchedResultCell.h"
#import <Parse/Parse.h>
@interface JobListViewController () <UISearchDisplayDelegate, UISearchBarDelegate> {
}
@property (nonatomic, weak) IBOutlet UISearchBar *searchedBar;
@property (nonatomic, strong) NSString *mainTitle;
@property (nonatomic, strong) NSString *subTitle;
@property (nonatomic, assign) BOOL canSearch;
@end
@interface JobListViewController ()
@end
@implementation JobListViewController
{}
@synthesize searchedBar;
@synthesize mainTitle;
@synthesize subTitle;
@synthesize canSearch;
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if (self) {
// 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 = 20;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.canSearch = 0;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
- (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);
}
- (void)objectsWillLoad {
[super objectsWillLoad];
// This method is called before a PFQuery is fired to get more objects
}
- (PFQuery *)queryForTable
{
PFQuery *query1 = [PFQuery queryWithClassName:@"Jobs"];
NSString *searchThis = [searchedBar.text capitalizedString];
[query1 whereKey:@"Position" containsString:searchThis];
PFQuery *query2 = [PFQuery queryWithClassName:@"Jobs"];
[query2 whereKey:@"Type" containsString:searchThis];
PFQuery *query = [PFQuery orQueryWithSubqueries:@[query1,query2]];
[query orderByDescending:@"createdAt"];
if (self.pullToRefreshEnabled) {
query.cachePolicy = kPFCachePolicyNetworkOnly;
}
// If no objects are loaded in memory, we look to the cache first to fill the table
// and then subsequently do a query against the network.
return query;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object: (PFObject *)object
{
static NSString *simpleTableIdentifier = @"JobCell";
static NSString *pimpleTableIdentifier = @"JobCell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
SearchedResultCell *bell = [self.tableView dequeueReusableCellWithIdentifier:pimpleTableIdentifier];
if (bell == nil) {
bell = [[SearchedResultCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:pimpleTableIdentifier];
}
[self configureSearchResult:bell atIndexPath:indexPath object:object];
}
// 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:@"showJobDetail"]) {
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"];
destViewController.job = job;
}
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[self clear];
self.canSearch = 1;
[self.searchedBar resignFirstResponder];
[self queryForTable];
[self loadObjects];
}
- (void)configureSearchResult:(SearchedResultCell *)cell atIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
mainTitle = [object objectForKey:@"Position"];
cell.mainTitle.text = mainTitle;
subTitle = [object objectForKey:@"Type"];
cell.detail.text = subTitle;
// Implement this if you want to Show image
cell.showImage.image = [UIImage imageNamed:@"AppIcon.png"];
PFFile *imageFile = [object objectForKey:@"imageFile"];
if (imageFile) {
cell.showImage.file = imageFile;
[cell.showImage loadInBackground];
}
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[searchedBar resignFirstResponder];
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
}
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
[self.searchedBar resignFirstResponder];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *) searchBar {
[self.searchedBar resignFirstResponder];
[self queryForTable];
[self loadObjects];
}
@end
Your code does not point to an existing job object
To add an object to a relation it should be an existing object on its table (if new object, you need to save it first)
UPDATE:
your code should use the property
job
in the view controller and add it to the current user relation as the followingIt would be better if you used Parse subclasses for Job object
then modify your code as the following