Does main queue get dispatched when app re-launches into background? - ios

My app makes use of UIBackgroundMode, i.e. it gets relaunched by iOS when Bluetooth events occur even while the app is not active. Therefore Bluetooth events are dispatched by iOS onto a background queue (queue is specified by me).
Can I however dispatch code back to the main queue, i.e.
DispatchQueue.main.async { } (Swift)
dispatch_async(dispatch_get_main_queue(), ^{ }) (Objective-C)
and assume that its run loop is running, that is my blocks get dispatched? Or is the main queue suspended in background mode and thus I should avoid adding dispatching blocks to it?

It should be safe to dispatch to the main queue while in the background.
When your app is in the background, everything it does is technically done on background threads because the system marks your app as a lower priority. However, in order for the system to let your code run it needs to at least have a main queue. Therefore, it is safe to assume you will have access to the main queue. You can create other work queues from there if you want, but everything will most likely be shoved onto the one background thread for execution, so you may not see much benefit.
Also note that testing background threading can be a little tricky. Background threads will always be executed and seem to never be shut down while in the simulator. The same happens when testing on a device if Xcode is connected and debugging. The system also lets your app run continuously for 10 minutes (last I checked, it's possible this has changed in the last year or two) after entering the background if needed, and after it will require something like the bluetooth event you mentioned to get additional time in the background.
Source: An unfortunate amount of experience dealing with backgrounded apps.

Related

iOS Background Task does not remain alive if launched when phone is locked (screen off)

I have an iOS application which interacts with BLE devices. The Bluetooth LE accessories background mode is active so that the application is able to connect and interact with BLE devices even when it's put in the background.
When a BLE device is connected, the application executes code in background responding to BLE-related callbacks, but after the BLE device disconnects the application can't run code in background anymore (the application remains alive only for a few seconds after BLE device disconnection).
What I need is a way to perform a finite-length task (1-2 min duration roughly) after the BLE device disconnects.
Reading Apple Documentation I tried using the beginBackgroundTaskWithExpirationHandler: method. Calling this method, the application should request some additional execution time (roughly 3 minutes).
Calling either of these methods delays the suspension of your app temporarily, giving it a little extra time to finish its work.
I tried to register the background task by calling the beginBackgroundTaskWithExpirationHandler responding to the BLE disconnection callback and I found out a strange behavior which depends on wether the phone is locked or not when the beginBackgroundTaskWithExpirationHandler is called:
If the phone is not locked (i.e., screen is on, app can be both visibile or in background) when beginBackgroundTaskWithExpirationHandler is called, the background task works as expected and remains alive for roughly 3 minutes when the application is later put in background and the screen is turned off.
If the phone is locked (screen off) when beginBackgroundTaskWithExpirationHandler is called, the background task do not remain active in background while the screen is off and it's somehow resumed when the screen is turned on again
(I tried with iPhone 6, iPhone 8 Plus, iPhone 5s all with iOS 12.1.4)
The approach I'm using is very similar to that described here, I also found here another similar problem.
Is that the intended behavior for background tasks? Do the OS suspend a background task if launched when the phone is in locked state?
Is there another way to start a finite-length task, with 1-2 minutes duration, from a callback which is triggered when the app is in background and the phone is locked?
Thank you in advance,
According to :
application(_:performFetchWithCompletionHandler:)
When this method is called, your app has up to 30 seconds of wall-clock time to perform the download operation and call the specified completion handler block. In practice, your app should call the completion handler block as soon as possible after downloading the needed data. If you do not call the completion handler in time, your app is terminated. More importantly, the system uses the elapsed time to calculate power usage and data costs for your app’s background downloads. If your app takes a long time to call the completion handler, it may be given fewer future opportunities to fetch data in the future.
So you have 30 seconds to finish any task you need in background.

How does the use of NSOperation mainqueue makes UITableView's scrolling smooth?

I wonder how the process associated with NSOperation mainQueue doesn’t affect UITableView's scrolling.
The main reason of the sluggish scroll in my code is that each cell loading is slow, because each cell has to fetch images from the server.
That’s why I used to create another thread using GCD to handle the fetching process given by each cell. Meanwhile, the main thread handles exclusively tableview’s scroll, which is what I've understood to ensure fast scrolling.
But, in recent days, I’ve noticed a sample code is using NSOperation.
I imitated the part so that the tableview cell is loaded using NSOperation mainQueue.
I expected it would tax the tableview’s scroll performance, because the main thread handles both cell loading and tableview scrolling as I understand.
But, surprisingly, it doesn’t. The performance of both cell loading and tableview’s scrolling is perfect.
I still wonder how this can be.
I guess I’m either mistaken or I miss something.
Would you let me know what it is?
All iOS UI animations (including scrolling) are performed on separate UI thread. So as long as UITableView has all required data (i.e. you provide empty cell until image is loaded) it won't be blocked by any sort of main thread activity.
Execution of the animations occurs on a secondary thread so as to
avoid blocking the current thread or your application’s main thread.
https://developer.apple.com/.../AnimatingViews.html
The iOS application's main thread consists of two elements:
• The Run Loop
• The Main Queue
The main dispatch queue is a globally available serial queue that
executes tasks on the application’s main thread. This queue works with
the application’s run loop (if one is present) to interleave the
execution of queued tasks with the execution of other event sources
attached to the run loop. Because it runs on your application’s main
thread, the main queue is often used as a key synchronization point
for an application.
Source
The code you have in your View Controllers is ran on the run loop (not sure about this one). That's why you're not allowed to execute any long lasting tasks.
You can though, delegate these tasks to the Main Queue (and that's what you're doing). When you do that, the OS interleaves the execution between the run loop and the main queue (loading the images). That's why scrolling the view is still pretty smooth.
Why don't we do all async tasks on the main queue then? you might ask. Because the main queue has to share thread processor time with the run loop, operations will be executed slower than on a background thread. It's not something that you can observe in that example, though.

How to schedule an asynchronous task every 'x' seconds when main and background thread need same data?

I have an iOS application that has an NSTimer which fires every 5 seconds. This then posts a notification, telling several controllers that they must now recalculate some data and then update their UI.
When this all happens on the main thread, scrollviews can become jittery as the data is processed.
Using GCD, I have wrapped the code called when a notification is posted:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Code here
dispatch_async(dispatch_get_main_queue(), ^(){
// Reload tableviews and UI
};
};
Unfortunately, this leads in certain cases to several threads accessing the same instance variables. This causes my application to crash as sometimes it ends up mutating an array being enumerated in another thread.
Wrapping the code in a synchronised block prevents this.
When the user scrolls the tableview, several methods are called to calculate the height etc, on the main thread. The code within the background thread is working on the code needed by the main thread. As such, this can usually further cause crashes
I have tried setting the variables to 'atomic', but this doesn't solve the issue. Ideally, I don't want to have the main thread waiting on the background thread, but I am not sure how to best resolve this issue given that they need the same data?
This is pretty classic multithreaded programming issues. There are a number of ways to solve it with basic locks (#synchronized blocks), reader/writer locks, etc but the problem is often that you can't control when the user is going to scroll or take other action. If you #synchronize, you have to do it anywhere that data is touched, including your UITableView data source methods. That can lead to stuttering if the background processing happens to be in the middle of something.**
Personally, I would use an immutable snapshot mechanism.
Have the background thread produce the results, then include just the data the UI needs to display in the notification data as an immutable snapshot (copy). That way the background thread never modifies the data the UI is currently reading for display. How you would implement this is highly dependent on how much data you are talking about and the form it takes, but the safe way would be to have copies of your classes with readonly properties. Alternatively, you can use a "frozen" flag. Make a copy, then set frozen = YES on the copy. The UI thread will only ever see "frozen" or readonly objects coming from the background thread.
The benefit is the UI never causes the background thread to stall and there are no locks required. The downside is increased memory usage, though if the amount of data is large you can use copy-on-write mechanisms to allow the background thread and UI thread to share the data, even though logically the UI thread has a completely separate copy.
** Note: In most applications, you don't have this sort of continuous background processing going on so those apps can use simpler mechanisms. This is typically a form of message passing where the background thread finishes its task and "passes the message" to the UI thread (passes the results). At that point the background work is finished so there is no concurrent modification happening.

How to prevent a pthread to be suspended in background mode on iOS

I have an app that functions perfectly well, with some background pthreads doing some networking stuff. However when the app goes in background mode, the threads are suspended. Is there anyway to prevent that or do I have to put them in the background task stuff?
Thanks

Preventing iOS clock from stopping

I have noticed that during very processor or memory intensive processes that my app is running, notably during initial download or executing a query, the clock inside the status bar will stop running and stay at the time that the process started. Is there any way to prevent this from happening, in case something like this causes the app to be rejected? I don't have any code to provide, as I am unsure to where the app does this at exactly.
Considering your comment, you should not perform memory-intensive or cpu-intensive work on the main thread. Only interactions with UI should be performed on the main thread, otherwise the UI will seem frozen, including your app and status bar.

Resources