How can we implement long running task in background in iOS? - ios

Recently I got requirement from my client that we need to process some execution in background. This execution may be for 10 min or 20 min long.
Is there any way to achieve this? I know iOS has listed few apps type & only those can be run in background. But I checked & my app is not fitting in that listed all apps type. So now I am doubtful in this.
Any one has solution?
Thanks
Shyam

// Try this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul), ^(void) {
// Perform long running process
dispatch_async(dispatch_get_main_queue(), ^{
// Update the UI
});
});
// Continue doing other stuff

Use Background fetch is available in Capabilities.
Background fetch mode is execute every 10 min.
Refer to the sample Code here : https://mobisoftinfotech.com/resources/mguide/background-fetch-ios/
Forgot this method beginBackgroundUploadTask from above tutorial.

Related

Background Service in Appcelerator titanium for iOS

I am facing some problem in background service.I have registered the backgrond service like:var service = Ti.App.iOS.registerBackgroundService({url:'/bgservice.js'});
in bgservice.js :I actually want to check the DB(where the data execution time is>8mins) and trigger local notification.But it is not working.So tried a sample first like this,to see how much time the app is active in background:
var timer = setInterval(startsampletest, 6000);
startsampletest();
function startsampletest(){
count=count+1;
Ti.API.info("1.!!!!!*******startsampletest is called for"+count);
}
which gives me only 5 times every 6 seconds so it is executing only for 30 min(please correct me if I am wrong)But in axway documentation it says the bgservice will be active for 10 mins.
Can anyone pls help me on this.I want the app to be active in background for 10 mins.pls let me know if I have made any mistakes.
It is not guaranteed that a background task created by Ti.App.iOS.registerBackgroundService() will run up to 10 minutes,
see: https://titaniumsdk.com/api/titanium/app/ios/backgroundservice.html#background-service-limitations
... typically to no more than 10 minutes.
But more crucial is that
The OS may terminate the background service at any point to reclaim resources.
For longer background tasks under iOS you have to use
the Ti.URLSession module (com.appcelerator.urlSession).
In general, see https://titaniumsdk.com/guide/Titanium_SDK/Titanium_SDK_How-tos/Platform_API_Deep_Dives/iOS_API_Deep_Dives/iOS_Background_Services.html

UI performance tax

I have this loop on a background thread, of which I want to inform the user of its progress.
So, in this loop, I call
[self performSelectorOnMainThread:#selector(updateProgressBarto:) withObject:#(value) waitUntilDone:YES];
I put some logging before and after the loop, and made the following observations:
If I enable the above line in order to show the progress, my logging console shows:
2017-06-17 16:43:49.675 myApp[8523:551864] Start Import
2017-06-17 16:43:59.119 myApp[8523:551864] Done Importing
that's a delta of roughly 9.5 seconds
without the progress bar, it looks like
2017-06-17 16:47:06.052 myApp[8611:556572] Start Import
2017-06-17 16:47:12.776 myApp[8611:556572] Done Importing
down to 6.7 seconds
As a comparison, if the loop is run in a Background Fetch, where there is no UI involved at all, logging shows:
2017-06-17 16:45:12.199 myApp[8523:553684] Start Import
2017-06-17 16:45:13.084 myApp[8523:553684] Done Importing
which is less than a second.
if I set
waitUntilDone:NO
I get the unwanted side effect that the progress bar is update only 3 times, rather than 50+ times.
The technical question: is this something I/the user has to live with, or are there any perceptional tricks to solve this?
The psychological question:
Would you/the user prefer six seconds without visual feedback over 9 seconds with feedback?
Your insights are very welcome.
why dont you do the UI update async using the GDC. There should be very little overhead in the background thread and little latency in the UI:
dispatch_async(dispatch_get_main_queue(), ^{
[self updateProgressBarto:#(value)];
});
Also, maybe you dont need to update the UI in every iteration, but only for every 10 or 100
if !(i % 10) {
// update UI progress bar
}

Multi threading in iOS objective C

I have a doubt regarding multi threading in iOS objective C. I have never worked on threads..
In my app, I have a couple of tasks that need to run only in background so that the UI doesn't get freezed.
Following is the code snippet,
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
[self someFunctionCallinWebservice];
dispatch_async(dispatch_get_main_queue(), ^(void){
//UI Updates
});
});
In the above code, function : someFunctionCallinWebservice calls webservice for which I am using AFNetworking library. In the webservice if it is a success then I am saving the data locally. I am calling a function in success block to save the data sent from server like below,
[manager POST:url parameters:parameter success:^(AFHTTPRequestOperation *operation, id responseObject){
[self functionToSaveData:someArray];
}
Here the someFunctionCallinWebservice is running in background but [self functionToSaveData:someArray] runs in foreground. Should I have this functionToSaveData also in background thread?
I mean if I am calling a function in background then all related functionalities of that function like, calling server, getting the data and saving it must also fall in background thread right? Why should I create another thread again?
Please help...
Yes, u can call functionToSaveData function in background thread it will not create any issue but if u want to do any UI updates (like :-> reload tableView, show or hide some views) at that time u must do it on main thread otherwise it will not do any effect on your UI.
dispatch_async(dispatch_get_main_queue(),^{
//Do any UI updates here
});
Edit: Swift 4
DispatchQueue.main.async {
//Do any UI updates here
}
Multi-threading is a large and difficult subject, for which iOS has different types of supports. I suggest you read Apple's Threading Programming Guide to start with.
For the type of action that you seem to be doing (fetching data from the internet), I suggest you use the iOS asynchronous APIs, such as URLSession, which remove the need to do anything with multi-threading yourself.
The answer to your concrete question depends on whether your POST:parameters:success: operation is a synchronous or an asynchronous operation, and it depends on what the functionToSaveData: actually does.
Assuming that functionToSaveData: is intended to share the data with the rest of your app, it would be best to do it on the main thread, to avoid synchronisation problems.

Using while(true) statement a valid approach in iOS programming?

In objective C,
I am making my program to wait using while loop
doInitialize()
{
dispach_group_t loadDataGroup=dispatch_group_create();
dispatch_group_async(loadDataGroup,...get_global_queue(..),0),^{
renewauth();
}
dispatch_group_notify(loadDataGroup,...get_global_queue(..),0),^{
//Do other tasks once renew session has completed...
}
}
renewauth()
{
RenewAuthTokenInProgress=true;
startRenewThread();
**while (RenewAuthTokenInProgress);**
}
In turn startRenewThread() function also performs dispatch_async operation inside. So I have to make renewAuth() wait.
And async task in startRenewThread will update the bool variable once renewal is successful.
Is there any better approach of doing it other than dispatch_groups?
And is it good to make other threads wait with while (true) statement?
Manoj Kumar,
using a while loop to wait till the boolean variable change is not the correct approach to solve the problem. Here are few of the issues with this method
Your CPU is un-necessarily burdened with checking the variable regularly.
This will clearly show that developer isn't much equipted with basic skills of coding and features available with language.
If for any reason your variable will never change then your CPU will never stop checking the value of bool in while loop and blocks the execution of further code on the same thread.
Here are few of the correct approach :
Blocks or closures : Make use of blocks to execute the code asynchronously when the RenewAuthToken is done.
Delegates : if blocks are harder to understand, Make use of delegates and trigger the delegate when you are done with RenewAuthToken.
Notifications : Add observer for notifications in classes which needs to respond when RenewAuthToken is done and throw notification from the asynctask and let the class to catch it execute the code.
Locks : If it is necessary to block the execution of the thread till the response comes use locks to control the thread execution rather than using while loop
EDIT
As pointed out by fogmeister in comments
If you block the main thread for too long with a while(true) loop then
the app will actually be terminated by the iOS Watchdog as it will
assume it has crashed
Please have a look at the link : understand iOS watchdog termination reasons provided by fogmeister
Hope it helps.
I believe what you need it's a semaphore like:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
__block BOOL done = FALSE;
while (true) {
[self someCompletionMethod completion:^(BOOL success) {
if(success) { // Stop condition
done = TRUE;
}
// do something
dispatch_semaphore_signal(sem); // This will let a new iteration
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
if(done) {
dispatch_async(dispatch_get_main_queue(), ^{
// Dispatch to main
NSLog(#"Done!");
break;
});
}
}
});
Semaphores are an old-school threading concept introduced to the world by the ever-so-humble Edsger W. Dijkstra. Semaphores are a complex topic because they build upon the intricacies of operating system functions.
You can see a tutorial here about semaphore and check it out more links: https://www.raywenderlich.com/63338/grand-central-dispatch-in-depth-part-2
I hope this can help you.
What you do is absolutely lethal. It blocks the running thread (presumably the main thread) so the UI is frozen. It runs one core at 100% load for no reason whatsoever which empties the battery rapidly and heats up the phone. This will get you some very, very unhappy customers or very, very happy ex-customers.
Anything like this has to run in the background: startRenewThread should trigger some action that sets RenewAuthTokenInProgress = NO and sets whether there is a new token or not, and then triggers further action.
This is an absolutely essential programming pattern on iOS (and Android as far as I know).

How to handle slow network connections with UIAutomation

I noticed that all my UI tests fail when the network is slow. For instance a user would try to login and then the next screen wouldn't load fast enough in order for another UIElement to be on screen.
How can I handle a slow network connection without using a delay() ?
You should definitely take a look at multi-threading. When handling network connections, you should make all this processing in a secondary thread. If not, the main thread will be blocked and the app will become unresponsive to the user.
Multi-threading is a very big subject. I recommend you to start looking at Apple's reference for this. You can also refer to a great course on iTunes U (lecture 11).
If you just want to give it a shot, here's the actual code (similar) that you will need:
dispatch_queue_t newQueue = dispatch_queue_create("networkQueue", NULL);
dispatch_async(newQueue, ^{
// here you need to call the networking processes
dispatch_async(dispatch_get_main_queue(), ^{
// if you need to update your UI, you need to get back to the main queue.
// This block will be executed in your main queue.
});
});
The only way I know of is using a delay. I usually have a activity indicator when loading stuff from the internet. So I add a delay while the activity indicator is displaying
while (activityIndicator.isVisible())
{
UIALogger.logMessage("Loading");
UIATarget.localTarget().delay(1);
}
Check out pushTimeout and popTimeout methods in the UIATarget. You can find the docs here.
Here is one code example from our iOS app UIAutomation tests:
// Tap "Post" button, which starts a network request
mainWindow.buttons()["post.button.post"].tap();
// Wait for maximum of 30 seconds to "OKAY" button to be valid
target.pushTimeout(30);
// Tap the button which is shown from the network request success callback
mainWindow.buttons()["dialog.button.okay"].tap();
// End the wait scope
target.popTimeout();

Resources