0
votes

I have painted myself into a corner and I need some help please!

Parse Class "Order" holds the data created when a User adds a Product to their Bag, including a PFObject Pointer for "jarName" which is pointing to the Parse Class "Jar" with String "jarName".

I need to display string "jarName" in a UILabel on a PFTableViewCell "OrderItemTableViewCell" sitting on a UITableViewController "BagTableViewController". But...and this is the corner I painted myself into..."OrderItemTableViewCell" uses the model "OrderItem", but "jarName" is not on the OrderItem model (or Parse Class), it is on the Order model and Parse Class "Order".

Parse Class Order holding Pointer jarName

jarName is a pointer to the Parse Class "Jar" for the string "jarName".

Parse Class Jar holding String jarName

The PFObjet jarName is created on the UITableViewController

@interface ProductDetailViewController ()

{
    PFObject* _selectedJar;
}

"ProductDetailViewController" when a user selects the Product they want to purchase, select the jarName associated with that Product and then adds them to their bag using a UIButton. The view then pops to BagTableViewController.

    //  ProductDetailViewController.m    
    - (void)didSelectAddToBagButton:(UIButton *)addToBagButton {
            if (![User currentUser]) {
                [self showWarning];
            } else {
                if (self.order) {
                    if ([self.order.items count] > 0) {
                        if ([self containsProduct:self.order.items target:self.product] > -1) {
                            int index = [self containsProduct:self.order.items target:self.product];
                            NSMutableArray *eItems = [NSMutableArray arrayWithArray:self.order.items];
                            OrderItem *foundItem = eItems[index];
                            [foundItem setQuantity:foundItem.quantity+1];
                            [eItems replaceObjectAtIndex:index withObject:foundItem];
                            self.order.items = [eItems copy];
                        } else {
                            [self.order addSingleProduct:self.product];
                        }
                    } else {
                        [self.order addSingleProduct:self.product];
                    }
                } else {
                    self.order = [Order object];
                    [self.order setCustomer:[User currentUser]];
                    [self.order setOrderStatus:ORDER_NOT_MADE];
                    [self.order addSingleProduct:self.product];
                    [self.order setJarName:_selectedJar];

                }
            }

BagTableViewController holds the view OrderItemTableViewCell which is populated by the data from the OrderItem model associated to the Parse Class OrderItem.

//  BagTableViewController.m

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 130;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.order.items count];
}

- (OrderItemTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    OrderItemTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BagItemCell" forIndexPath:indexPath];
    if (self.order) [cell configureItem:self.order.items[indexPath.row] tag:indexPath.row];
    else [cell configureItem:nil tag:100+indexPath.row];
        return cell;
}

So, here is the rub...

I need to populate a UILabel inside the OrderItemTableViewCell with data from the Parse Class Order while 4 other labels are being populated by data from the Parse Class OrderItem.

//  OrderItemTableViewCell.m

@interface OrderItemTableViewCell()
@property (nonatomic, weak) IBOutlet UILabel *jarNameLabel;
@property (nonatomic, weak) IBOutlet UILabel *nameLabel;
@property (nonatomic, weak) IBOutlet UILabel *unitPriceLabel;
@property (nonatomic, weak) IBOutlet UILabel *quantityLabel;
@property (nonatomic, weak) IBOutlet UIStepper *quantityStepper;
@end

@implementation OrderItemTableViewCell

    -(void)configureItem:(OrderItem *)item tag:(long)tag{
        if (item) {

            self.nameLabel.text = item.product.name;
            self.unitPriceLabel.text = [item.product friendlyPrice];
            self.quantityLabel.text = [item friendlyQuantity];
            self.quantityStepper.hidden = NO;
            self.quantityStepper.value = item.quantity;
            self.quantityStepper.stepValue = 1;
            self.quantityStepper.tag = tag + 100;
        } else {
            self.nameLabel.text = @"";
            self.unitPriceLabel.text = @"";
            self.quantityLabel.text = @"";
            self.quantityStepper.hidden = YES;
        }
    }
@end

So basically, I have a Pointer in a different class that I need to retrieve and display the String as a UILabel.

(1) How do I query the Pointer "jarName" from the Parse Class Order and have it return the String "jarName" from the Parse Class "Jar"?

(2) How do I display that String on the UILabel in the OrderItemTableViewCell (which is populated by the OrderItem model...which does not contain the string or pointer)?

1

1 Answers

0
votes

If I'm understanding your question correctly ... You call FetchIfNeeded to populate pointer objects nested inside a PFObject. This works, I use it all time to populate pointers, and the objects and values inside pointers of pointers of pointers of ... etc. etc. You can nest as many pointers as you'd like, just call this this method on the pointer object, wait for completion, and then set the object in the place where the pointer is.

Example:

PFObject * orderObjectFromOrderClass = [PFObject objectWithClassName:@"Order"];
[[orderObjectFromOrderClass objectForKey:@"jarName"] fetchIfNeededInBackgroundWithBlock:^(PFObject * _Nullable object, NSError * _Nullable error) {
    if (!error) {
        [orderObjectFromOrderClass setObject:object forKey:@"jarName"];
    }
}];

NSString * jarName = [[orderObjectFromOrderClass objectForKey:@"jarName"] valueForKey:@"jarName"];

Key Note:

If you fail to fetch the pointers using FetchIfNeeded then an error will be thrown that you need to call "FetchIfNeeded" on that pointer object FIRST because the value doesn't exist. So, if you have a class with pointers and YOU'VE NOT QUERIED those pointers using PFQuery and the "includeKey" (with or without dot notation depending on what your needs are) then the PFObject that you're calling to WILL NOT have the data for those pointer objects. YOU MUST call FetchIfNeeded if you've not yet fleshed out those pointer values.

Update, define the NSString inside like so to make sure you have a value for the NSString

PFObject * orderObjectFromOrderClass = [PFObject objectWithClassName:@"Order"];
    [[orderObjectFromOrderClass objectForKey:@"jarName"] fetchIfNeededInBackgroundWithBlock:^(PFObject * _Nullable object, NSError * _Nullable error) {
        if (!error) {
            [orderObjectFromOrderClass setObject:object forKey:@"jarName"];
            NSString * jarName = [[orderObjectFromOrderClass objectForKey:@"jarName"] valueForKey:@"jarName"];
            // set your cell lable text here to make sure there's a value for "jarName" from the pointer
        }
    }];