Ken
Ken

Reputation: 31171

UIPageControl and delay in appearing

How do I make an instance of UIPageControl appear immediately? (I have set defersCurrentPageDisplay to NO.)

I have an instance of UIPageControl which is configured (number of pages, current page and then updated) when my view appears. However there is a short, fixed delay before it appears to the user. I'd like it to appear right away.

Otherwise it's working fine.

Upvotes: 0

Views: 786

Answers (2)

rcat24
rcat24

Reputation: 538

I have fixed the delay issue by adding the UIPageViewController delegate's willTransitionToViewControllers and setting the pageController's index there:

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers {
for (MyContentPageViewController *contentController in pendingViewControllers) {
    if ([contentController isKindOfClass:[MyContentPageViewController class]]) {
        NSUInteger newIndex = contentController.pageIndex;
        [self.pageControl setCurrentPage:newIndex];
    }
}

Then, to avoid bugs in cases where swipe is not completed, add the following delegate method:

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{
if(finished){
    for (MyContentPageViewController *contentController in previousViewControllers) {
        if ([contentController isKindOfClass:[MyContentPageViewController class]]) {
            NSUInteger currentIndex = MIN(MAX(0, contentController.pageIndex), _allPages.count- 1);
            [self.pageControl setCurrentPage:currentIndex];
        }
    }
} else {
    for (MyContentPageViewController *contentController in previousViewControllers) {
        if ([contentController isKindOfClass:[MyContentPageViewController class]]) {
            NSUInteger currentIndex = MIN(MAX(0, contentController.pageIndex), _allPages.count);
            [self.pageControl setCurrentPage:currentIndex];
        }
    }
}

}

Upvotes: 1

Ken
Ken

Reputation: 31171

The problem is I'm performing a lengthy background process and I've inadvertently and ultimately called updateCurrentPageDisplay etc. from this secondary thread. UIKit is not thread-safe and blocks this call until it can move it to the main thread, hence the delay.

To solve this, I've subclassed UIPageControl creating "wrapper" methods that push calls to super onto the main thread. I can then safely forget about this every time I need to speak with my page controls.

For example:

- (void) updateCurrentPageDisplay
{
  @synchronized(self)
  {
    if ([UIDevice currentDeviceSupportsGrandCentralDispatch] == YES)
    {
      dispatch_async(dispatch_get_main_queue(), ^{
        [super updateCurrentPageDisplay];
      });
    }
    else
    {
      [super performSelectorOnMainThread:@selector(updateCurrentPageDisplay)
                              withObject:nil
                           waitUntilDone:NO];
    }
  }
}

Upvotes: 2

Related Questions