When terminating a handler with background radiation in iOS 7 with NSOperation

I want to integrate background selection in my iOS application, I turned on Background Fetch in the project features, then I insert this:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum]; 

to enable background selection with the minimum interval, and then in the application deletion I insert the delegate method:

 -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { NSLog(@"Call fetch iCloud"); [[MySingleton sharedManager] startCheckOnCloud]; } 

My question is that I know what I should call it:

 completionHandler(UIBackgroundFetchResultNewData); 

somewhere, I see many examples that insert this performFetchWithCompletionHandler completion method into the performFetchWithCompletionHandler delegate performFetchWithCompletionHandler , but in this method I call NSOperation in Singleton , this operation checks the iCloud che folder and makes some changes to Sqlite DB if I do this:

  -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { NSLog(@"Call fetch iCloud"); [[MySingleton sharedManager] startCheckOnCloud]; completionHandler(UIBackgroundFetchResultNewData); } 

start work and do something, maybe because the system makes it sleep instantly, instead, if I remove checkHandler, give me this warning:

 Warning: Application delegate received call to -application:performFetchWithCompletionHandler: but the completion handler was never called. 

so my question is: how can I handle completionHandler using NSOperation ?

+6
source share
4 answers

You should call the completion handler with 30 seconds, but you do not need to block the main thread during the execution of the request.

It seems that inside UIKit detects that you are not storing a strong link to completeHandler, and then log this warning. If you do something simple:

 - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // Start asynchronous NSOperation, or some other check // Ideally the NSOperation would notify when it has completed, but just for // illustrative purposes, call the completion block after 20 seconds. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ // Check result of your operation and call completion block with the result completionHandler(UIBackgroundFetchResultNewData); }); } 

You will notice that the warning is not even logged, although the method exited before the completion block was called.

+6
source

I had a similar situation in my application. What I did was pass the completion handler to my singleton and whenever my code path is completed, either with success or with an error, I check to see if there is a link to the completion block. if so, I just call the completion handler with the corresponding results; if not, it means that I am not in the background fetch mode. Remember to include the completion handler link for nil in your singleton mode after the guardians, because it can trick your instance into subsequent operations. I did something else, because of this mandatory 30 second timeout in the background, before starting my work, I check if the background fetch mode is on, if so, I plan a timer for 25 seconds (5 second threshold to guarantee) and deal with the situation yourself. if you don’t do this and your application will not be able to complete the 30 second timeout if you call the exit handler too many times, you will end up blocking your application from the background fetch on the user device. good luck

+6
source

At some point, your application will know when it will load and process new data. This can be whenever a new file is stored on disk, new records are inserted into Core Data, or when the web page has finished loading.

Once this happens, you must determine if there really was new data, and then call the completion handler with the correct argument. Most likely, this means that you have to pass the completion handler to other objects. startCheckOnCloud will become startCheckOnCloudWithCompletionHandler: and if this method is not the one that actually performs the selection, you pass the completion handler to the method that is called in startCheckOnCloudWithCompletionHandler: which performs the selection.

+1
source

I also have this problem, I finally decided that my error was that due to the presence of an asynchronous operation in the fetch callback, when you start using the __block UIBackgroundFetchResult assignment for this:

 UIBackgroundFetchResult __block result = UIBackgroundFetchResultNoData; result = UIBackgroundFetchResultNoData; post: return; return; because, "did not lead to finally, the method is called," completionHandler (result); " 

so this is a mistake: "the completion handler was never called", "return", get rid of the final call methods: "completeHandler (result)", no error. In the summary, you must call the method: completeHandler (); cannot be a mistake.

thanks.

0
source

Source: https://habr.com/ru/post/958699/


All Articles