# What is the correct way to call UIApplication.shared.beginBackgroundTask no on the main thread?

**URL:** <https://forums.swift.org/t/what-is-the-correct-way-to-call-uiapplication-shared-beginbackgroundtask-no-on-the-main-thread/75196>\
**Category:** Using Swift\
**Tags:** concurrency, uikit, mainactor, actor\
**Created:** [October 7, 2024, 5:19am UTC](https://forums.swift.org/t/what-is-the-correct-way-to-call-uiapplication-shared-beginbackgroundtask-no-on-the-main-thread/75196 "2024-10-07T05:19:54Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![nomnom](https://avatars.discourse-cdn.com/v4/letter/n/3d9bf3/32.png) [@nomnom](https://forums.swift.org/u/nomnom)\
**Post date:** [October 7, 2024, 5:19am UTC](https://forums.swift.org/t/what-is-the-correct-way-to-call-uiapplication-shared-beginbackgroundtask-no-on-the-main-thread/75196/1 "2024-10-07T05:19:54Z")

</div>

This is my newbie implementation for beginBackgroundTask

```swift

@MainActor
class BackgroundTaskManager {
    var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid

    func startBackgroundTask() {
        backgroundTaskID = UIApplication.shared.beginBackgroundTask {
            print("Background task about to expire with \(UIApplication.shared.backgroundTimeRemaining)")
            UIApplication.shared.endBackgroundTask(self.backgroundTaskID)
        }
        print("Started background task with \(UIApplication.shared.backgroundTimeRemaining)")
    }
    
    func endBackgroundTask() {
        UIApplication.shared.endBackgroundTask(backgroundTaskID)
    }
}

```

When I search online, I see that apple has commented on their forum that these methods in fact does not need to be called from the main thread. But if I were to remove @MainActor and just make this class an actor instead, I get these warnings:

Main actor-isolated class property 'shared' can not be referenced on a nonisolated actor instance; this is an error in the Swift 6 language mode

Actor-isolated property 'backgroundTaskID' can not be referenced from the main actor; this is an error in the Swift 6 language mode

Ideally, I dont want to isolate to main, as that's an extra dependencies for my background jobs.

---

<div class="post-metadata">

**Author:** ![vns](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vns/32/37396_2.png) [@vns](https://forums.swift.org/u/vns)\
**Post date:** [October 9, 2024, 12:42pm UTC](https://forums.swift.org/t/what-is-the-correct-way-to-call-uiapplication-shared-beginbackgroundtask-no-on-the-main-thread/75196/3 "2024-10-09T12:42:34Z")

</div>

You can make both methods `async` and get instance of the `UIApplication`:

```swift
func startBackgroundTask() async {
    let app = await UIApplication.shared
    backgroundTaskID = app.beginBackgroundTask { /* ... */ }
}

```

Some of APIs in UIKit and related parts are questionable at the moment (another example is `UIDevice` which got a few topics here as well). And this is really a bit of a complication here to just call an API from the background. I think over time this will get an improvement, but right now you can use a workaround.

> [@dima\_kozhinov](#):
>
> I'm not a structured concurrency expert, so please correct me if I'm wrong, but do we have Actor Helltm already?

It's just a difficulties bridging old (largely ObjC still I guess) systems. I don't think it is anything to blame at all, just a transition case.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [October 10, 2024, 10:23pm UTC](https://forums.swift.org/t/what-is-the-correct-way-to-call-uiapplication-shared-beginbackgroundtask-no-on-the-main-thread/75196/4 "2024-10-10T22:23:20Z")

</div>

> [@dima\_kozhinov](#):
>
> Actor Helll™

What's that?

---

<div class="post-metadata">

**Author:** ![dima\_kozhinov](https://avatars.discourse-cdn.com/v4/letter/d/258eb7/32.png) [@dima\_kozhinov](https://forums.swift.org/u/dima_kozhinov)\
**Post date:** [October 11, 2024, 9:57am UTC](https://forums.swift.org/t/what-is-the-correct-way-to-call-uiapplication-shared-beginbackgroundtask-no-on-the-main-thread/75196/5 "2024-10-11T09:57:30Z")

</div>

A kind of a mess created by good intentions. Not sure if the term already exists, or I just coined it. the tm mark was intended as a joke.

---

<div class="post-metadata">

**Author:** ![eskimo](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/eskimo/32/13558_2.png) [@eskimo](https://forums.swift.org/u/eskimo)\
**Post date:** [October 11, 2024, 3:31pm UTC](https://forums.swift.org/t/what-is-the-correct-way-to-call-uiapplication-shared-beginbackgroundtask-no-on-the-main-thread/75196/6 "2024-10-11T15:31:21Z")

</div>

nomnom wrote:

> I see that apple has commented on their forum that these  
> methods in fact does not need to be called from the main  
> thread.

It’s more official than that. In the Objective-C header these methods are decorated with `NS_SWIFT_NONISOLATED`, which is why you’re able to call them from non-main-actor contexts.

vns wrote:

> You can make both methods `async` and get instance of the  
> `UIApplication`:

That’ll work, but it requires bouncing to the main thread, which undermines the purpose of making this API thread safe.

I kinda like this approach:

```start
actor BackgroundTaskManager {

    @MainActor
    init() {
        self.app = UIApplication.shared
    }
    
    let app: UIApplication
    
    func runJob(name: String) {
        let t = self.app.beginBackgroundTask(withName: name) {
            … handle expiration …
        }
        defer {
            if t != .invalid {
                self.app.endBackgroundTask(t)
            }
        }
        … do something …
    }
}

```

Of course the expiry handler is main actor isolated, courtesy of the `NS_SWIFT_UI_ACTOR` decoration in the header, which is another tricky complication )-:

Honestly, I’m not a fan of these APIs [1] and I encourage you to file an [enhancement request](https://developer.apple.com/forums/thread/712889) for a better option.

Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

[1] Although I’m even less of a fan of the `ProcessInfo` API that app extensions have to use. I talk about this in [UIApplication Background Task Notes](https://developer.apple.com/forums/thread/85066).

---

<div class="post-metadata">

**Author:** ![vns](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vns/32/37396_2.png) [@vns](https://forums.swift.org/u/vns)\
**Post date:** [October 11, 2024, 3:52pm UTC](https://forums.swift.org/t/what-is-the-correct-way-to-call-uiapplication-shared-beginbackgroundtask-no-on-the-main-thread/75196/7 "2024-10-11T15:52:51Z")

</div>

> [@eskimo](#):
>
> ```swift
> @MainActor
> init() {
> self.app = UIApplication.shared
> }
> 
> ```

That’s a clever way to handle this, thanks for sharing! Might be useful in other cases as well.
