i want integrate the Background Fetch in my iOS app, i have enabled the Background Fetch in the capabilities of the project, then i have insert this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
to enable the background fetch with minimum interval, then in App delegate i insert the delegate method:
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(#"Call fetch iCloud");
[[MySingleton sharedManager] startCheckOnCloud];
}
My question is this, i know that i have to call this:
completionHandler(UIBackgroundFetchResultNewData);
somewhere, i have see a lot of example that insert that completionHandler in the performFetchWithCompletionHandler delegate method, but in that method i call a NSOperation in a Singleton, that operation check che iCloud folder and make some changes in a Sqlite DB, if i do this:
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(#"Call fetch iCloud");
[[MySingleton sharedManager] startCheckOnCloud];
completionHandler(UIBackgroundFetchResultNewData);
}
the operation start and do anything, maybe because the system make it sleep instantly, instead if i remove the completionHandler give me this warning:
Warning: Application delegate received call to -application:performFetchWithCompletionHandler: but the completion handler was never called.
so my question is, how i can handle the completionHandler with NSOperation?
You must call the completion handler with 30 seconds, but you don't have to block the main thread while you perform the query.
It appears that internally UIKit is detecting that you have not stored a strong reference to the completionHandler and then logging that warning. If you perform something simple like this:
- (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 isn't logged even, though the method exited before calling the completion block.
I've had similar situation in my app too.
What I did was to pass the completion handler to my singleton and whenever my code path has ended in operation, either on success or error, I check if I have a reference to a completion block. if so, I simply call the completion handler with appropriate results, if not, that means I'm not in background fetch mode.
Don't forget to set your completion handler's reference to nil in your singleton after wards, because it might fool your instance in the consequent operations.
I did something else too, because of that mandatory 30 second timeout on background fetch, before starting my operation, I check if I'm in background fetch mode, if so, I schedule a timer for 25 seconds (5 second threshold for assurance) and handle the situation myself. if you don't do this, and your app fails to meet 30 second timeout on calling completion handler too many times, you'll end up blocking your app from background fetch on the user's device.
good luck
At some point, your app will know when it's done fetching and processing new data. That can be whenever a new file was stored to disk, new records were inserted in Core Data, or when a web page finished loading.
As soon as that happens, you have to determine whether there was indeed new data, and then call the completion handler with the correct argument. More than likely, that means that you'll have to pass the completion handler to other objects. startCheckOnCloud will become startCheckOnCloudWithCompletionHandler:, and if that method isn't the one to actually do the fetch, you pass the completion handler to a method that gets called in startCheckOnCloudWithCompletionHandler: that does do the fetch.
I also have this problem, I finally solved my mistake is that, due to the presence of the asynchronous operation in the fetch callback, when you start using __block UIBackgroundFetchResult assignment to this:
UIBackgroundFetchResult __block result = UIBackgroundFetchResultNoData;
result = UIBackgroundFetchResultNoData;
post: return; return; because, "did not lead to finally, the method is called," completionHandler (result); "
so it appears a mistake:" the completion handler was never called "," return; "get rid of making the final call methods:" completionHandler (result); "there is no mistake. Under the summary, is must call the method: completionHandler (); can not be wrong.
Thx.
Related
My Question is - Does dispatch_async fire immediately? I'm seeing that the creating thread has to return before dispatch_async fires.
My issue is that I am trying to make a async call to a 3rd party library appear to be synchronous. I know, I know... I should allow these async operations run as intended but I'm trying to do this way down in a complex multi-threaded operation and I really don't have a choice.
here's what starts the async call
-(void)connect
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) , ^{
[device connect];
});
while(!connectCompleted)
{
NSLog(#"Sleeping..");
[NSThread sleepForTimeInterval:1.0];
}
}
and here's the delegate function that gets called AFTER the [device connect] successfully connects:
- (void)didConnect:(BXPrinterController *)controller
printer:(BXPrinter *)printer
{
connectCompleted = YES;
NSLog(#"didConnect");
}
with that dispatch_async wrapped around [device connect] the delegate never gets fired;
Does dispatch_async fire immediately
Of course not! That is what async means! The whole basis of the concept "asynchronous" (which is what async stands for) is that this is code that runs at some future unspecified time. Meanwhile the code that calls dispatch_async continues on to its end without waiting.
If for whatever reason you must make a call appear synchronous, I'd recommend that you first implement it synchronously (because you'll end up doing that anyway if people had enough of delays), and then you write a helper method that is synchronous:
Step 1: Create a dispatch_semaphore_t.
Step 2: Start the asynchronous code, with every code path ending by sending a signal to the dispatch_semaphore_t.
Step 3: Send a wait to the dispatch_semaphore_t. It wakes up, with no CPU time spent on it at all, just when the asynchronous code finishes.
I'm using NSOperationQueue and a subclass of NSOperation for a part in my app that is generating a lot of data and therefore is very calculation-heavy.
When the app is closed by the user processingQueue.cancelAllOperations() is called. Also in my NSOperation subclass I overwrote cancel() to let it forward a cancel request to the class that does the actual heavy lifting ...
override func cancel() {
AppDelegate.instance.cancelDataGeneration()
super.cancel()
}
But this is still not enough. When I close the app while the data generation is ongoing it will crash in Xcode.
What can I do to prevent the crashing (which might result in data loss)? Is it OK to let the app wait for closing until all concurrent operations are canceled and how is this done (if it's even possible)? Or what other methods are generally used to address this issue?
UPDATE:
After more investigation I found that cancel() on my NSOperation subclass is never called, even after calling processingQueue.cancelAllOperations() in applicationShouldTerminate. So I added a method to manually call cancel on it:
func cancelDataGeneration() {
if let op = AppDelegate.instance._operation {
op.cancel();
}
}
And I call this from inside applicationShouldTerminate (since applicationShouldTerminate is called earlier than applicationWillTerminate. Interestingly, since my AppDelegate is a Singleton I have to use AppDelegate.instance._operation. If I only check for _operation it results in being nil when called from applicationShouldTerminate. Would be interesting to know why this is the case.
In any case, canceling now works properly: When the app is quit, it will cancel the data generation class and exits without crashing ... mostly anyway. But I still wonder why my NSOperation subclass' cancel() isn't called when I use processingQueue.cancelAllOperations()!
From Apple's documentation.
Canceling the operations does not automatically remove them from the queue or stop those that are currently executing. For operations that are queued and waiting execution, the queue must still attempt to execute the operation before recognizing that it is canceled and moving it to the finished state.
I would block the App's mainthread until the NSOperationQueue finishes all of its work.
I would call [NSOperationQueue cancelAllOperations] first.
Then in the 'Application will terminate' method I will call
[NSOperationQueue waitUntilAllOperationsAreFinished]. This will make sure the currently executing block(all the other queued tasks will be cancelled) will complete before the application quits.
Now if you are not comfortable with the main thread blocking until the currently executing block finishes, then you need to check for a flag(or an NSApplicationDelegate could be set on that class) which signals if the application is still active in order to continue. If application is to be terminated, then fall out of the block voluntarily, this is the cleanest way to do it.
Something roughly like the below.
void ^(aBlock)(void) = ^void(void)
{
for(NSUInteger i = 0;i < 1000; i++)
{
// heavy processing code. Taking several iterations each second
// At the start of each iteration, check for a flag, to see if to quit
if(_applicationIsShuttingDown) break;
// perform block operation
}
};
and your class is an NSApplicationDelegate and implements
-applicationWillTerminate:(NSNotification *)aNotification
{
_applicationIsShuttingDown = YES;
}
In my code, I am running a local server (CocoaHTTPServer). When the server receives a request, it creates a thread and passes control to a certain method ( - (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path, perhaps irrelevant here).
I need to read a list of local assets and return the result. The API call ( [assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) ... ) is asynchronous.
Since the HTTPResponse needs to wait until the API call has finished, I have created a flag called _isProcessing , which I set before making the API call. After the call is finished, I am unsetting the flag and returning the HTTP request. The code to wait looks like:
// the API call is non-blocking. hence, wait in a loop until the command has finished
samCommand->isProcessing = YES;
while (samCommand->isProcessing) {
usleep(100*1000);
}
The API call calls a delegate method upon finishing its task as follows:
// to be called at the end of an asynch operation (eg: reading local asset list)
- (void) commandDidFinish {
// flag to open the lock
isProcessing = NO;
}
This works, but will perhaps require performance enhancements. How can I use anything (run-loop etc) here to improve upon the performance.
Edit following weichsel solution using dispatch_semaphore
Following weichsel's solution, I created a semaphore. The sequence of my code is:
CocoaHTTPServer receives a request and hence creates a new thread
It calls the static method of a Command class to execute the request
The Command class creates a new command Object calls another class (using reflection) which calls ALAsset APIs and passes the command Object to it
Upon returning, the ALAsset API call calls the delegate method of
the command class
I have hence embedded semaphores in appropriate locations. However, the semaphore's wait loop just doesnt end sometimes. The normal output should be:
2014-02-07 11:27:23:214 MM2Beta[7306:1103] HTTPServer: Started HTTP server on port 1978
2014-02-07 11:27:23:887 MM2Beta[7306:6303] created semaphore 0x1f890670->0x1f8950a0
2014-02-07 11:27:23:887 MM2Beta[7306:6303] calling execute with 0x1f890670
2014-02-07 11:27:23:887 MM2Beta[7306:6303] starting wait loop 0x1f890670->0x1f8950a0
2014-02-07 11:27:23:887 MM2Beta[7306:907] calling getAssetsList with delegate 0x1f890670
2014-02-07 11:27:24:108 MM2Beta[7306:907] calling delegate [0x1f890670 commandDidFinish]
2014-02-07 11:27:24:108 MM2Beta[7306:907] releasing semaphore 0x1f890670->0x1f8950a0
2014-02-07 11:27:24:109 MM2Beta[7306:6303] ending wait loop 0x1f890670->0x0
In every few runs, the last step ( ending wait loop 0x1f890670->0x0 doesnt occur). Hence, the wait loop never ends. Sometimes the code crashes too, exactly at the same point. Any clue what is wrong here.
My code is as follows:
#implementation SAMCommand {
NSData* resultData;
dispatch_semaphore_t semaphore; // a lock to establish whether the command has been processed
}
// construct the object, ensuring that the "command" field is present in the jsonString
+(NSData*) createAndExecuteCommandWithJSONParamsAs:(NSString *)jsonString {
SAMCommand* samCommand = [[SAMCommand alloc] init];
samCommand.commandParams = [jsonString dictionaryFromJSON];
if(COMPONENT==nil || COMMAND==nil){
DDLogError(#"command not found in %#",jsonString);
return nil;
}
samCommand->semaphore = dispatch_semaphore_create(0);
DDLogInfo(#"created semaphore %p->%p",samCommand,samCommand->semaphore);
// to execute a command contained in the jsonString, we use reflection.
DDLogInfo(#"calling execute with %p",samCommand);
[NSClassFromString(COMPONENT) performSelectorOnMainThread:NSSelectorFromString([NSString stringWithFormat:#"%#_%#_%#:",COMMAND,MEDIA_SOURCE,MEDIA_TYPE]) withObject:samCommand waitUntilDone:NO];
// the above calls are non-blocking. hence, wait in a loop until the command has finished
DDLogInfo(#"starting wait loop %p->%p",samCommand,samCommand->semaphore);
dispatch_semaphore_wait(samCommand->semaphore, DISPATCH_TIME_FOREVER);
DDLogInfo(#"ending wait loop %p->%p",samCommand,samCommand->semaphore);
DDLogInfo(#"");
// return the data
return samCommand->resultData;
}
// to be called at the end of an asynch operation (eg: reading local asset list)
- (void) commandDidFinish {
// flag to release the lock
DDLogInfo(#"releasing semaphore %p->%p",self,semaphore);
dispatch_semaphore_signal(semaphore);
semaphore = nil;
}
#end
I got it to work :)
Finally, what seems to work stably is creating the semaphore, and passing it to the ALAsset asynch API calls, and releasing it at the end of the call. Earlier, I was calling a delegate method of the class where I had created the semaphore, and the semaphore object was somehow getting releases. Unsure of what was happening there really.
You can use semaphore to block execution of the current queue until another one returns.
The basic pattern is:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[assetsLibrary enumerateAssetsUsingBlock^(ALAsset *result, NSUInteger index, BOOL *stop):^{
...
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);
You can find a full example of this method in Apple's MTAudioProcessingTap Xcode Project:
https://developer.apple.com/library/ios/samplecode/AudioTapProcessor
The relevant lines start at MYViewController.m:86
NSRunLoop has a method called runUntilDate: which should work for you with dates in near future like 1s ahead or so. That way you can replace your sleep call in the while loop for example with:
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeintervalSinveNow:1]
I have an Cocoa Application (Mac OS X SDK 10.7) that is performing some processes via Grand Central Dispatch (GCD). These processes are manipulating some Core Data NSManagedObjects (non-document-based) in a manner that I believe is thread safe (creating a new managedObjectContext for use in this thread).
The problem I have is when the user tries to quit the application while the dispatch queue is still running.
The NSApplication delegate is being called before actually quitting.
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
I get an error "Could not merge changes." Which is somewhat expected since there are still operations being performed through the different managedObjectContext. I am then presented with the NSAlert from the template that is generated with a core data application.
In the Threading Programming Guide there is a section called "Be Aware of Thread Behaviors at Quit Time" which alludes to using replyToApplicationShouldTerminate: method. I'm having a little trouble implementing this.
What I would like is for my application to complete processing the queued items and then terminate without presenting an error message to the user. It would also be helpful to update the view or use a sheet to let the user know that the app is performing some action and will terminate when the action is complete.
Where and how would I implement this behavior?
Solution:
So I had a few different issues here.
I had blocks that were accessing core data in a dispatch_queue preventing my application from terminating gracefully.
When I tried to add a new item to the dispatch_queue a new instance of the dispatch_queue was started on a new thread.
What I did to solve this was use NSNotificationCenter in my AppDelegate (where (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender was being called. In the template code that Core Data generates add the following:
// Customize this code block to include application-specific recovery steps.
if (error) {
// Do something here to add queue item in AppController
[[NSNotificationCenter defaultCenter] postNotificationName:#"TerminateApplicationFromQueue" object:self];
return NSTerminateLater;
}
Then in AppController add an observer for the notification (I added this to awakeFromNib):
- (void)awakeFromNib {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(terminateApplicationFromQueue:) name:#"TerminateApplicationFromQueue" object:nil];
// Set initial state of struct that dispatch_queue checks to see if it should terminate the application.
appTerminating.isAppTerminating = NO;
appTerminating.isTerminatingNow = NO;
}
I have also created a struct that can be checked against to see if the user wants to terminate the application. (I set the initial state of the struct in awakeFromNib above). Place the struct after your #synthesize statements:
struct {
bool isAppTerminating;
bool isTerminatingNow;
} appTerminating;
Now for the long-running dispatch_queue that is preventing the app from gracefully terminating. When I initially create this dispatch_queue, a for loop is used to add the items that need updating. After this for loop is executed, I have tacked on another queue item that will check the struct to see if the app should terminate:
// Additional queue item block to check if app should terminate and then update struct to terminate if required.
dispatch_group_async(refreshGroup, trackingQueue, ^{
NSLog(#"check if app should terminate");
if (appTerminating.isAppTerminating) {
NSLog(#"app is terminating");
appTerminating.isTerminatingNow = YES;
}
});
dispatch_release(refreshGroup);
And the method to be called when the notification is received:
- (void)terminateApplicationFromQueue:(NSNotification *)notification {
// Struct to check against at end of dispatch_queue to see if it should shutdown.
if (!appTerminating.isAppTerminating) {
appTerminating.isAppTerminating = YES;
dispatch_queue_t terminateQueue = dispatch_queue_create("com.example.appname.terminate", DISPATCH_QUEUE_SERIAL); // or NULL
dispatch_group_t terminateGroup = dispatch_group_create();
dispatch_group_async(terminateGroup, terminateQueue, ^{
NSLog(#"termination queued until after operation is complete");
while (!appTerminating.isTerminatingNow) {
// add a little delay before checking termination status again
[NSThread sleepForTimeInterval:0.5];
}
NSLog(#"terminate now");
[NSApp replyToApplicationShouldTerminate:YES];
});
dispatch_release(terminateGroup);
}
}
I haven't dealt with this myself, but just from my reading of the docs, it looks like what you should do is:
Return NSTerminateLater from applicationShouldTerminate:. This lets the system know that your app isn't ready to terminate just yet, but will do so shortly.
Enqueue a "final" block on your dispatch queue. (You need to make sure that other blocks are not enqueued after this. This block will then be run after all the other work has been performed. Note the queue must be serial -- not one of the concurrent queues) for this to work correctly.) The "final" block should do [NSApp replyToApplicationShouldTerminate:YES];, which will complete the normal termination process.
There isn't any direct way to find out whether a GCD queue is still working. The only other thing that you can do (that I know of) to handle this is to put all of the blocks into a dispatch group, and then wait on the group in applicationShouldTerminate: (using dispatch_group_wait().
In my application, I let a progress indicator starts animation before I send a HTTP request.
The completion handler is defined in a block. After I get the response data, I hide the progress indicator from inside the block. My question is, as I know, UI updates must be performed in the main thread. How can I make sure it?
If I define a method in the window controller which updates UI, and let the block calls the method instead of updating UI directly, is it a solution?
Also, if your app targets iOS >= 4 you can use Grand Central Dispatch:
dispatch_async(dispatch_get_main_queue(), ^{
// This block will be executed asynchronously on the main thread.
});
This is useful when your custom logic cannot easily be expressed with the single selector and object arguments that the performSelect… methods take.
To execute a block synchronously, use dispatch_sync() – but make sure you’re not currently executing on the main queue or GCD will deadlock.
__block NSInteger alertResult; // The __block modifier makes alertResult writable
// from a referencing block.
void (^ getResponse)() = ^{
NSAlert *alert = …;
alertResult = [NSAlert runModal];
};
if ([NSThread isMainThread]) {
// We're currently executing on the main thread.
// We can execute the block directly.
getResponse();
} else {
dispatch_sync(dispatch_get_main_queue(), getResponse);
}
// Check the user response.
if (alertResult == …) {
…
}
You probably misunderstood something. Using blocks doesn't mean that your code is running in a background thread. There are many plugins that work asynchronously (in another thread) and use blocks.
There are a few options to solve your problem.
You can check if your code is running in the main thread my using [NSThread isMainThread]. That helps you to make sure that you're not in the background.
You can also perform actions in the main or background by using performSelectorInMainThread:SEL or performSelectorInBackground:SEL.
The app immediately crashes when you're trying to call the UI from a bakcground thread so it's quite easy to find a bug.