Last active
June 5, 2024 20:09
-
-
Save steipete/30c33740bf0ebc34a0da897cba52fefe to your computer and use it in GitHub Desktop.
Mac Catalyst: Get the NSWindow from a UIWindow (Updated for macOS 11 Big Sur, also works with Catalina)
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
// Don't forget to prefix your category! | |
#import <UIKit/UIKit.h> | |
NS_ASSUME_NONNULL_BEGIN | |
@interface UIWindow (PSPDFAdditions) | |
#if TARGET_OS_UIKITFORMAC | |
/** | |
Finds the NSWindow hosting the UIWindow. | |
@note This is a hack. Iterates over all windows to find match. Might fail. | |
*/ | |
@property (nonatomic, readonly, nullable) id nsWindow; | |
#endif | |
@end | |
NS_ASSUME_NONNULL_END |
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 "UIWindow+PSPDFAdditions.h" | |
@implementation UIWindow (PSPDFAdditions) | |
#if TARGET_OS_UIKITFORMAC | |
- (nullable NSObject *)nsWindow { | |
id delegate = [[NSClassFromString(@"NSApplication") sharedApplication] delegate]; | |
const SEL hostWinSEL = NSSelectorFromString([NSString stringWithFormat:@"_%@Window%@Window:", @"host", @"ForUI"]); | |
@try { | |
// There's also hostWindowForUIWindow 🤷♂️ | |
PSPDF_SILENCE_CALL_TO_UNKNOWN_SELECTOR(id nsWindow = [delegate performSelector:hostWinSEL withObject:self];) | |
// macOS 11.0 changed this to return an UINSWindowProxy | |
let attachedWin = NSSelectorFromString([NSString stringWithFormat:@"%@%@", @"attached", @"Window"]); | |
if ([nsWindow respondsToSelector:attachedWin]) { | |
nsWindow = [nsWindow valueForKey:NSStringFromSelector(attachedWin)]; | |
} | |
return nsWindow; | |
} @catch (...) { | |
NSLog(@"Failed to get NSWindow for %@.", self); | |
} | |
return nil; | |
} | |
#endif | |
@end |
This works great. just need to be sure to let the UI settle down with delays before you try to access the window. Using these to lock the aspect ratio in a MacCatalyst app:
delay(2) {
cover.removeFromSuperview()
#if targetEnvironment(macCatalyst)
let ns = window.nsWindow
let frame = ns?.value(forKey: "frame")
let size = (frame as! CGRect).size
ns!.setValue(CGSize(1.0, size.height/size.width), forKey: "aspectRatio")
#endif
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a cleaner code using Dynamic:
And this is the first approach: