Guides and Sample Code

Developer

Energy Efficiency Guide for Mac Apps

On This Page

Prioritize Work at the App Level

You can distinguish discretionary work that your app initiates on its own from lengthy user-initiated activities, such as exporting files or recording audio. Doing so allows the system to make intelligent decisions about how to properly manage your app, including when it should be placed in App Nap.

Inform the System About Lengthy User-Initiated Activities

Use an NSProcessInfo object to classify the different types of work your app performs. Before performing asynchronous operations, call the beginActivityWithOptions:reason: method, and pass the returned object to endActivity: when the activity is finished.

The options parameter for the beginActivityWithOptions:reason: method describes the type of activity your app is performing. If your app is doing lengthy user-initiated work, pass the NSActivityUserInitiated or NSActivityUserInitiatedAllowingIdleSystemSleep constant, as demonstrated in Listing 9-1. Denoting user-initiated work prevents the system from deferring the operations or putting your app in App Nap. If your app is performing discretionary or maintenance work, pass the NSActivityBackground constant.

Listing 9-1Calling the beginActivityWithOptions method to inform the system of a user activity

Objective-C

  1. NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
  2. id myActivity = [[NSProcessInfo processInfo]
  3. beginActivityWithOptions: NSActivityUserInitiated
  4. reason: @"Batch processing files"];
  5. [myQueue addOperationWithBlock:^{
  6. // Perform batch processing of files here
  7. [[NSProcessInfo processInfo] endActivity:myActivity];
  8. }];

Swift

  1. let myQueue = NSOperationQueue()
  2. let myActivity = NSProcessInfo.processInfo().beginActivityWithOptions(
  3. NSActivityOptions.UserInitiated,
  4. reason: "Batch processing files")
  5. myQueue.addOperationWithBlock() {
  6. // Perform batch processing of files here
  7. NSProcessInfo.processInfo().endActivity(myActivity)
  8. }
  9. )

For long-running synchronous operations, call the performActivityWithOptions:reason:usingBlock: method instead. Again, specify the type of activity—user-initiated or background—and perform its work inside the block. The method runs the block synchronously and automatically begins and ends the activity around the block.

Determine When Your App Is Preventing Sleep

Launch Activity Monitor in /Applications/Utilities/ and check the Preventing Sleep column (Figure 9-1). If this column isn’t visible, choose View > Columns > Power Assertion to display it.

Figure 9-1Using Activity Monitor to determine when an app is preventing sleep image: ../Art/activitymonitor_preventsleep_2x.png

You can also use Terminal to see whether your processes have any power assertions in effect while running your app. To do so, enter the command pmset -g assertions. In Listing 9-2, prevention of user idle and system sleep are asserted by an app. The debug string "Batch processing files" reported in the output is supplied in the reason parameter to beginActivityWithOptions:reason:, as shown in Listing 9-1.

Listing 9-2Testing for power management assertions
  1. $ pmset -g assertions
  2. Assertion status system-wide:
  3. BackgroundTask 0
  4. PreventUserIdleDisplaySleep 0
  5. PreventSystemSleep 0
  6. PreventDiskIdle 0
  7. PreventUserIdleSystemSleep 1
  8. ExternalMedia 0
  9. UserIsActive 0
  10. ApplePushServiceTask 0
  11. Listed by owning process:
  12. pid 3741(Fire): [0x00001ae700010591] 00:13:44 PreventUserIdleSystemSleep
  13. named: "Batch processing files"