Questions regarding performExpiringActivityWithReason: and other activities

Hi,


I need to use background task assertions for an extension. As such, it is recommended to use ProcessInfo's performExpiringActivityWithReason: method.


I've a few questions:

  1. Can I call this method as soon as I start performing the work in the foreground, like this is recommended for beginBackgroundTask:expirationHandler: (i.e. even if the extension never moves to the background) or should I call it only as the extension enters the background?
  2. Can I have multiple background task assertions like with beginBackgroundTask:expirationHandler: ?
  3. Beyond the expiration handler, are there any difference with the other activity methods (beginActivityWithOptions:reason:/endActivity: and performActivityWithOptions:reason:usingBlock:)?
  4. In my main app, can I use both UIApplication's beginBackgroundTask:expirationHandler: and ProcessInfo's activity methods (see last question)?
  5. Does the activity option NSActivityUserInitiated prevents the app/extension to be suspended as soon as it enters the background, or does it has another use/behavior?
  6. What's the difference between sudden termination and automatic termination?
  7. Are the flags NSActivitySuddenTerminationDisabled and NSActivityAutomaticTerminationDisabled automatically infered when using the NSActivityBackground or NSActivityUserInitiated options? If not, can I use them together?
  8. Which method and flags should I use around file operations?
  9. Can I use nested activities? For example (pseudo-code):


beginActivityWithOptions:reason: (or UIApplication's background task for main app)

    performExpiringActivityWithReason: { /*work that should not be interrupted in the middle (e.g. could lead to data corruption)*/ }

    // user-initiated, non-cancellable work that should attempt to complete even after the extension moves to the background.
    // Interrupting this work in the middle has no side-effects like data corruption.

    performExpiringActivityWithReason: { /*work that should not be interrupted in the middle (e.g. could lead to data corruption)*/ }

endActivity:

Thanks.

Accepted Reply

1. Can I call this method as soon as I start performing the work in the foreground …?

Yes.

2. Can I have multiple background task assertions … ?

Yes.

3. Beyond the expiration handler, are there any difference with the other activity methods …?

Yes. These are very different beasts and if the goal is to keep your process from being suspended after moving to the background on iOS then I recommend that you stick with

-performExpiringActivityWithReason:usingBlock:
. The expiry handler is critical, as discussed in my UIApplication Background Task Notes post.

4. In my main app, can I use both UIApplication's

-beginBackgroundTask:expirationHandler:
and
ProcessInfo
’s activity methods (see last question)?

Yes.

5. Does the activity option

NSActivityUserInitiated
prevents the app/extension to be suspended as soon as it enters the background, or does it has another use/behavior?

See my answer to question 3.

6. What's the difference between sudden termination and automatic termination?

IIUC they are synonyms but, regardless, these are macOS concepts that don’t apply to iOS.

7. Are the flags

NSActivitySuddenTerminationDisabled
and
NSActivityAutomaticTerminationDisabled
automatically infered when using the
NSActivityBackground
or
NSActivityUserInitiated
options? If not, can I use them together?

See my answers to questions 3 and 6.

8. Which method and flags should I use around file operations?

See my answer to question 3.

9. Can I use nested activities?

Your pseudocode doesn’t make sense because of my answer to question 3, but in general I think it’s safe to nest operations like this. However, I don’t think this is a good approach. It’s better to deal with these constructs once, at the top level of your code, than to repeat that work at each level.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

1. Can I call this method as soon as I start performing the work in the foreground …?

Yes.

2. Can I have multiple background task assertions … ?

Yes.

3. Beyond the expiration handler, are there any difference with the other activity methods …?

Yes. These are very different beasts and if the goal is to keep your process from being suspended after moving to the background on iOS then I recommend that you stick with

-performExpiringActivityWithReason:usingBlock:
. The expiry handler is critical, as discussed in my UIApplication Background Task Notes post.

4. In my main app, can I use both UIApplication's

-beginBackgroundTask:expirationHandler:
and
ProcessInfo
’s activity methods (see last question)?

Yes.

5. Does the activity option

NSActivityUserInitiated
prevents the app/extension to be suspended as soon as it enters the background, or does it has another use/behavior?

See my answer to question 3.

6. What's the difference between sudden termination and automatic termination?

IIUC they are synonyms but, regardless, these are macOS concepts that don’t apply to iOS.

7. Are the flags

NSActivitySuddenTerminationDisabled
and
NSActivityAutomaticTerminationDisabled
automatically infered when using the
NSActivityBackground
or
NSActivityUserInitiated
options? If not, can I use them together?

See my answers to questions 3 and 6.

8. Which method and flags should I use around file operations?

See my answer to question 3.

9. Can I use nested activities?

Your pseudocode doesn’t make sense because of my answer to question 3, but in general I think it’s safe to nest operations like this. However, I don’t think this is a good approach. It’s better to deal with these constructs once, at the top level of your code, than to repeat that work at each level.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thank you very much for your useful answers.


It appears that ProcessInfo's

-performExpiringActivity:withReason:using:
was added with iOS 8.2, the same SDK version that solved common issues for sharing data between a container app and its extension. Since this method can be used in both targets, as well as in frameworks, does it still make sense to use the older UIApplication's
-beginBackgroundTask:expirationHandler:
? Can I only use the ProcessInfo's equivalent or are there subtle differences between the two I'm not aware of (beyond the syntax)?


these are macOS concepts that don’t apply to iOS.

The fact the related flags are available on the iOS platform is quite confusing. Are there cases where

beginActivity(options:reason:)
would be useful on iOS?

does it still make sense to use the older

UIApplication
’s
-beginBackgroundTask:expirationHandler:
?

Personally, I find the

UIApplication
API much easier to use, so I default to that unless I happen to be in an environment, like an app extension, where I can’t use it.

The problem with the

ProcessInfo
API is that the activity ends when you return from the closure, so it’s less than ideal when the activity is asynchronous, like a network request. In that situation you end up having to do the standard async-to-sync dance:
  1. Start the async operation.

  2. Block the thread.

  3. When the async operation has finished, unblock the thread.

This is extra code and it wastes a Dispatch thread.

Regardless, the effect of these two APIs is basically the same: They both take out a background task assertion.

The fact the related flags are available on the iOS platform is quite confusing.

Agreed.

Are there cases where

beginActivity(options:reason:)
would be useful on iOS?

I’m struggling to think of any, but I must admit I haven’t looked into these in great depth. Most folks in your situation are primarily interested in background task assertions, and it’s not safe to make such an assertion without also supplying an expiry handler, and thus only APIs with an expiry handler are relevant IMO.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

A UIApplication's like API for ProcessInfo would have been useful, especially when writing frameworks.


Thank you again.

A

UIApplication
like API for
ProcessInfo
would have been useful, especially when writing frameworks.

Agreed. I’d appreciate you making a formal request for this. Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I've filed a report: #42330957.