Created
May 7, 2025 06:39
-
-
Save lunacookies/e9ce5bb2117d4fe0224fa9996ef9645f to your computer and use it in GitHub Desktop.
Combining view controller lifecycle methods and window occlusion notifications to pause invisible work
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @import AppKit; | |
| @import os.log; | |
| @interface MainViewController : NSViewController | |
| @end | |
| @implementation MainViewController { | |
| NSTextField *_label; | |
| id<NSObject> _occlusionObserver; | |
| NSTimer *_timer; | |
| } | |
| - (void)loadView { | |
| [super loadView]; | |
| _label = [NSTextField labelWithString:@"hello world"]; | |
| _label.translatesAutoresizingMaskIntoConstraints = NO; | |
| NSView *view = self.view; | |
| [view addSubview:_label]; | |
| [NSLayoutConstraint activateConstraints:@[ | |
| [_label.centerXAnchor constraintEqualToAnchor:view.centerXAnchor], | |
| [_label.centerYAnchor constraintEqualToAnchor:view.centerYAnchor], | |
| [_label.leadingAnchor constraintGreaterThanOrEqualToAnchor:view.leadingAnchor], | |
| [_label.trailingAnchor constraintLessThanOrEqualToAnchor:view.trailingAnchor], | |
| ]]; | |
| } | |
| - (void)viewWillAppear { | |
| [super viewWillAppear]; | |
| os_log_debug(OS_LOG_DEFAULT, "viewWillAppear"); | |
| [self viewBecameVisible]; | |
| } | |
| - (void)viewDidAppear { | |
| [super viewDidAppear]; | |
| os_log_debug(OS_LOG_DEFAULT, "viewDidAppear"); | |
| if (_occlusionObserver == nil) { | |
| NSWindow *window = self.view.window; | |
| _occlusionObserver = [NSNotificationCenter.defaultCenter | |
| addObserverForName:NSWindowDidChangeOcclusionStateNotification | |
| object:window | |
| queue:nil | |
| usingBlock:^(NSNotification *notification) { | |
| if (window.occlusionState & NSWindowOcclusionStateVisible) { | |
| os_log_debug(OS_LOG_DEFAULT, "window became visible"); | |
| [self viewBecameVisible]; | |
| } else { | |
| os_log_debug(OS_LOG_DEFAULT, "window became hidden"); | |
| [self viewBecameHidden]; | |
| } | |
| }]; | |
| } | |
| } | |
| - (void)viewWillDisappear { | |
| [super viewWillDisappear]; | |
| os_log_debug(OS_LOG_DEFAULT, "viewWillDisappear"); | |
| } | |
| - (void)viewDidDisappear { | |
| [super viewDidDisappear]; | |
| os_log_debug(OS_LOG_DEFAULT, "viewDidDisappear"); | |
| [self viewBecameHidden]; | |
| [NSNotificationCenter.defaultCenter removeObserver:_occlusionObserver]; | |
| _occlusionObserver = nil; | |
| } | |
| - (void)dealloc { | |
| os_log_debug(OS_LOG_DEFAULT, "=== DEALLOC ==="); | |
| } | |
| - (void)viewBecameVisible { | |
| dispatch_assert_queue(dispatch_get_main_queue()); | |
| [self updateLabel]; | |
| if (_timer == nil) { | |
| _timer = [NSTimer scheduledTimerWithTimeInterval:0.1 | |
| repeats:YES | |
| block:^(NSTimer *timer) { | |
| [self updateLabel]; | |
| }]; | |
| os_log_debug(OS_LOG_DEFAULT, "started timer"); | |
| } | |
| } | |
| - (void)viewBecameHidden { | |
| dispatch_assert_queue(dispatch_get_main_queue()); | |
| if (_timer != nil) { | |
| os_log_debug(OS_LOG_DEFAULT, "stopping timer %@...", _timer); | |
| [_timer invalidate]; | |
| _timer = nil; | |
| os_log_debug(OS_LOG_DEFAULT, "stopped timer"); | |
| } | |
| } | |
| - (void)updateLabel { | |
| dispatch_assert_queue(dispatch_get_main_queue()); | |
| os_log_debug(OS_LOG_DEFAULT, "update label"); | |
| _label.stringValue = [NSDate date].description; | |
| } | |
| @end | |
| @interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate> | |
| @end | |
| @implementation AppDelegate { | |
| NSWindow *_window; | |
| } | |
| - (BOOL)applicationOpenUntitledFile:(NSApplication *)sender { | |
| _window = [NSWindow windowWithContentViewController:[[MainViewController alloc] init]]; | |
| _window.delegate = self; | |
| [_window makeKeyAndOrderFront:nil]; | |
| return YES; | |
| } | |
| - (void)windowWillClose:(NSNotification *)notification { | |
| _window = nil; | |
| } | |
| @end | |
| int main(void) { | |
| [NSApplication sharedApplication]; | |
| NSApp.activationPolicy = NSApplicationActivationPolicyRegular; | |
| AppDelegate *appDelegate = [[AppDelegate alloc] init]; | |
| NSApp.delegate = appDelegate; | |
| [NSApp run]; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment