2

I added to my app On-Demand Resources and posted to app store. Part of my users has trouble, a block completionHandler called when the resources have finished downloading doesn't occurs. It doesn't deppend on disc space. In most cases it works right.

Once I have the same truoble, I reset my iPhone content, reinstll app, and trouble is left.

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
             NSSet *tags = [NSSet setWithObjects: self.exerciseId, nil];
             resourceRequest = [[NSBundleResourceRequest alloc] initWithTags:tags];
             [resourceRequest conditionallyBeginAccessingResourcesWithCompletionHandler:
              ^(BOOL resourcesAvailable)
              {

                  if (resourcesAvailable) {
                      dispatch_async(dispatch_get_main_queue(), ^{
                          [self setupMoviePlayerVideoWithName:_exerciseId];
                      });
                  }
                  else {
                      [self tryToGetODR];
                  }
              }];    
}


  -(void) tryToGetODR{
           resourceRequest.loadingPriority = NSBundleResourceRequestLoadingPriorityUrgent;
            [resourceRequest beginAccessingResourcesWithCompletionHandler: ^(NSError * __nullable error){
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if (error) {

                            return;
                        }
                        [self.videoImageView setHidden:true];
                        [self.activityIndikator setHidden:true];
                        [self.downloadProgressLabel setHidden:true];
                        [self setupMoviePlayerVideoWithName:_exerciseId];

                    });
                }];
    }

Anybody faced with similar?

Ivan
  • 191
  • 1
  • 2
  • 11

1 Answers1

0

The sporadic nature of the problem is immediately suggestive of a threading issue. And indeed, you have one. Change:

else {
    [self tryToGetODR];
}

to:

else {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self tryToGetODR];
    });
}

Otherwise (among other bad things) you are trying to access resourceRequest and launch the non-conditional access on a background thread. This means you don't give the first request (the conditional request) a chance to complete.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thank you a lot! I try it, but I don't understand what did you mean "Otherwise (among other bad things) you are trying to access resourceRequest and launch the non-conditional access on a background thread. This means you don't give the first request (the conditional request) a chance to complete." Could you explain please – Ivan Dec 02 '16 at 02:59
  • concretely why first request hasn't a chance to complete? – Ivan Dec 02 '16 at 03:08
  • You are effectively calling `beginAccessingResourcesWithCompletionHandler` from _inside_ `conditionallyBeginAccessingResourcesWithCompletionHandler`. So the completion handler has not yet returned and you are trying to start a new request. That's not necessarily going to work. The documentation is quite clear about this! — Plus you are now talking to an instance property from two different threads simultaneously, which is always a bad idea. – matt Dec 02 '16 at 03:35