Reputation: 157
I have a table view loaded with products. The price for each needs some heavy calculation so I would like to this outside the main UI thread because otherwise scrolling the table is very very jumpy almost impossible. no matter what I try I cannot get the syntax and the concept right. My current code does load the price on the background but when I scroll some cells are given prices which do not belong to them. I am not sure how to debug this. Any suggestions appreciated.
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([self.products count] == 0) {
UITableViewCell *cell = [[UITableViewCell alloc] init];
return cell;
}
AvailableCustomerProductTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.buttonAdd.tag = indexPath.row;
[cell.buttonAdd addTarget: self action: @selector(addToSelectedProduct:) forControlEvents: UIControlEventTouchUpInside];
Product *prod = nil;
if (theTableView == self.searchDisplayController.searchResultsTableView) {
prod = (Product *)[self.filteredProducts objectAtIndex:indexPath.row];
} else {
prod = (Product *)[self.products objectAtIndex:indexPath.row];
}
if (prod != nil) {
cell.pNumber.text = prod.number;
cell.description.text = prod.desc;
if ([Common getProductPromotion:prod] != nil) {
cell.btnPromotionTag.hidden = NO;
cell.btnPromotionTag.tag = indexPath.row;
[cell.btnPromotionTag addTarget: self action: @selector(showPromotionDetails:) forControlEvents: UIControlEventTouchUpInside];
}
else{
cell.btnPromotionTag.hidden = YES;
}
//Get the customer product price, first:
//If if the product has a record in the productCustomerPrices list
//if not get the price from the standard price.
if (self.order.orderOrderCustomer != nil) {
// Do the Customer price fetching in a background thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CustomerPrice *custPrice = [Common getPriceForCustomer:self.order.orderOrderCustomer.customerId forProduct:prod.productId inManagedObjectContext:self.backgroundContext];
// Return to the main thread to update the UI
dispatch_async(dispatch_get_main_queue(), ^{
if (custPrice) {
NSManagedObjectID *objId = custPrice.objectID;
CustomerPrice *custPrice = (CustomerPrice*)[self.managedObjectContext objectWithID:objId];
if (custPrice) {
// Check that the relevant data is still required and get the correct cell (it might have changed)
AvailableCustomerProductTableViewCell * correctCell = nil;
if ([[theTableView indexPathsForVisibleRows] containsObject:indexPath]) {
correctCell = (AvailableCustomerProductTableViewCell*)[self.tableView cellForRowAtIndexPath:indexPath];
}
[correctCell.btnPrice setTitle:[Common getCurrencyFormattedStringFromFloat:[custPrice.price floatValue]] forState:UIControlStateNormal];
[correctCell.btnPrice setTitleColor:[UIColor colorWithRed:0.01 green:0.65 blue:0.77 alpha:1] forState:UIControlStateNormal];
correctCell.btnPrice.enabled = NO;
[correctCell setNeedsLayout];
} }
});
});
}
}
UISwipeGestureRecognizer* sgr = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(cellSwiped:)];
[sgr setDirection:UISwipeGestureRecognizerDirectionRight];
[cell addGestureRecognizer:sgr];
return cell;
}
Upvotes: 0
Views: 237
Reputation: 6022
Have you tried to do this in several steps :
viewWillAppear:
)Load your products list to display the ListView quickly, NSDictionary*prices
with productId
for key. When the calculation is over, you should call [self.tableView reloadData]
on the main thread !cellForRowAtIndexPath:
method, then you should only check if you have the price in you prices
dictionary and display your button. Be sure to hide the button if you have no price, to avoid display glitches when the cell is recycled.Like this, you avoid some complex reload by line and association causing probably your problems.
Upvotes: 1