Search code examples
iosobjective-cdelegatesnsurlsessionnsurlsessionuploadtask

UI Slow to Update *ONLY* If Called In Response To Change Occurring in NSURLSessionUploadTask Completion Block


The app interacts with php scripts on my server. A user can create a booking, and details are written to a database. Subsequently, they can cancel that booking.

Within the app, a booking is an object, responsible for gathering its own details from the server. A booking can also cancel itself (at the user's request) - pressing "the cancel button" in BookingViewController calls the booking's (void)cancelBooking method, which posts to bookings-cancel.php using an NSURLSessionUploadTask with json data rolled from @{ @"invoiceNumber": self.invoiceNumber }.

The database is updated, the uploadSession returns new details, and the booking updates itself according. All of this is nicely responsive - up and back in less than a second, consistently.

The problem comes when I attempt to update the UI on BookingViewController (labels for delivery date and price) using values read from the booking object after it has updated itself (within the uploadSession completion block).

BookingViewController is assigned as the booking's delegate. The booking is setup for KVO on its own "price" property. Whenever the price changes, the booking calls a delegate method priceDidChange:(NSString *)updatedPrice on BookingViewController, triggering an NSLog and updates to deliveryLabel.text and priceLabel.text.

- (void)priceDidUpdate:(NSString *)updatedPrice {
    NSLog(@"priceDidUpdate delegate notification - updatedPrice is: %@", updatedPrice);
    [self.deliveryLabel setText:@"N/A"];
    [self.priceLabel setText:updatedPrice];
}

Testing has shown that if I update the price directly from the "cancel" button, or with any other explicit command (e.g., self.price = @"123.45") within the cancelBooking method outside of the uploadTask, then the UI updates just as quickly as the NSLog is written out (i.e., near instantaneously).

However, if the price is updated within the uploadTask completion block, the NSLog will write out just as responsively but the updates to deliveryLabel.text and priceLabel.text are very slow to occur - the delay varies between 5 and 12 seconds, approximately.

I've got NSLogs all over the place, and am confident this is not merely about a delay getting the updated value to or from the booking object. Easily twenty times already I have seen "priceDidUpdate delegate notification - updatedPrice is: 0.00" (the updated price), then counted to 10 before self.priceLabel.text is actually set to @"0.00". Totally stumped.

In case it matters, the NSURLSession is configured using ephemeralSessionConfiguration with no adjustments.

Is there any reason why the UI updates in BookingViewController should take longer to occur based on whether or not the call to priceDidChange comes from inside or outside the uploadTask completion block?

Thanks in advance!


Solution

  • Use main queue to update the UI. Use following code:

    - (void)priceDidUpdate:(NSString *)updatedPrice 
    {
        dispatch_async(dispatch_get_main_queue(), ^()
        {
                //Add method, task you want perform on mainQueue
                //Control UIView, IBOutlet all here
                NSLog(@"priceDidUpdate delegate notification - updatedPrice is: %@", updatedPrice);
                [self.deliveryLabel setText:@"N/A"];
                [self.priceLabel setText:updatedPrice];
        });
    }