10

How do I disable app nap in Swift? Im new to programming and I am building a timer(just for practice), and I am afraid app nap will break my timer.

Vitor Loureiro
  • 101
  • 1
  • 3
  • Not sure what the app nap is but are you looking for [idleTimerDisabled](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html#//apple_ref/occ/instp/UIApplication/idleTimerDisabled)? – Desdenova Dec 26 '14 at 12:50
  • idleTimerDisabled seems to only work on iOS App. Mine is OSX application. AppNap is a technology that apple introduced with Mavericks OS X to low energy consumption – Vitor Loureiro Dec 26 '14 at 18:30
  • My bad, didn't notice OS X tag. – Desdenova Dec 27 '14 at 10:37

4 Answers4

7

I found that this solution works in Swift as well.

Create a class or global variable

var activity: NSObjectProtocol?

And assign it after which App Nap will be disabled

activity = NSProcessInfo().beginActivityWithOptions(NSActivityOptions.UserInitiated, reason: "Good Reason")
Community
  • 1
  • 1
Mellson
  • 2,918
  • 1
  • 21
  • 23
5

Swift 3:

var activity: NSObjectProtocol?

and

activity = ProcessInfo().beginActivity(options: ProcessInfo.ActivityOptions.userInitiated, reason: "Good Reason")
Yura Voevodin
  • 412
  • 6
  • 10
5

Swift 4.x / 5.3:

For ProcessInfo.ActivityOptions, Apple's documentation describes:

static var userInitiated

Flag to indicate the app is performing a user-requested action.

static var userInitiatedAllowingIdleSystemSleep

Flag to indicate the app is performing a user-requested action, but that the system can sleep on idle.

Unless your intention is to prevent the system from sleeping, you should use userInitiatedAllowingIdleSystemSleep.

Steps

  1. Retain reference in a scope that will survive until any point you may want to revert the change (ie: within AppDelegate)

     var activity: NSObjectProtocol?
    
  2. Run this, possibly in AppDelegate applicationDidFinishLaunching:

     activity = ProcessInfo.processInfo.beginActivity(options: .userInitiatedAllowingIdleSystemSleep, reason: "Good Reason")
    

To cancel and re-enable App Nap at any time:

if let pinfo = activity {
    ProcessInfo.processInfo.endActivity(pinfo)
}
stef
  • 952
  • 10
  • 15
0

None of the previous 3 answers to this question correctly use ProcessInfo class. As per ProcessInfo documentation:

Each process has a single, shared ProcessInfo object, known as a process information agent. The processInfo type property [previously class method] returns the shared agent for the current process.

processInfo documentation explains it further:

The object is created the first time this property [previously method] is invoked, and that same object is returned on each subsequent invocation.

Otherwise you refer to different instances of ProcessInfo object when beginning and ending activity (you must end activity), what can lead to incorrect behaviour. Thus the correct code in Swift 5 is:

let activity = ProcessInfo.processInfo.beginActivity(options: .userInitiatedAllowingIdleSystemSleep, reason: "Timer")
// Perform some work
ProcessInfo.processInfo.endActivity(activity)

While the details of the app and timer implementation are unknown, it's hard to say whether this approach is correct in your case. Please also consider these notes:

If your activity takes place synchronously inside an event callback on the main thread, you do not need to use this API.

Be aware that failing to end these activities for an extended period of time can have significant negative impacts to the performance of your user's computer, so be sure to use only the minimum amount of time required. User preferences may override your application’s request.

Usage of Timer object (and bringing in some tolerance if possible) may be a more correct approach. System (and its App Nap feature) should account for the timer. Testing and Activity Monitor will tell you.

stasswtf
  • 153
  • 1
  • 6