Просмотр исходного кода

Refactor keyWindow-related logic

First, we give FLEXUtility some methods to grab the app's keyWindow (and the active UIWindowScene on iOS 13).

Now, FLEXWindow will use this method to store the previous keyWindow as it becomes the new keyWindow. Other view controllers which need to reference the keyWindow will simply call self.window.previousKeyWindow (where self.window is a new property added to FLEXTableViewController).

Now, we don't need to go hunting for it anywhere else, and we don't need to hold a reference to it in FLEXGlobalsTableViewController.
Tanner Bennett лет назад: 6
Родитель
Сommit
239afdbd7c

+ 11 - 8
Classes/Core/Controllers/FLEXTableViewController.h

@@ -7,7 +7,7 @@
 //
 //
 
 
 #import <UIKit/UIKit.h>
 #import <UIKit/UIKit.h>
-@class FLEXScopeCarousel;
+@class FLEXScopeCarousel, FLEXWindow;
 
 
 typedef CGFloat FLEXDebounceInterval;
 typedef CGFloat FLEXDebounceInterval;
 /// No delay, all events delivered
 /// No delay, all events delivered
@@ -29,7 +29,7 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
 >
 >
 
 
 /// A grouped table view. Inset on iOS 13.
 /// A grouped table view. Inset on iOS 13.
-/// 
+///
 /// Simply calls into initWithStyle:
 /// Simply calls into initWithStyle:
 - (id)init;
 - (id)init;
 
 
@@ -43,7 +43,7 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
 @property (nonatomic) FLEXScopeCarousel *carousel;
 @property (nonatomic) FLEXScopeCarousel *carousel;
 
 
 /// Defaults to NO.
 /// Defaults to NO.
-/// 
+///
 /// Setting this to YES will initialize searchController and the view.
 /// Setting this to YES will initialize searchController and the view.
 @property (nonatomic) BOOL showsSearchBar;
 @property (nonatomic) BOOL showsSearchBar;
 /// Defaults to NO.
 /// Defaults to NO.
@@ -53,7 +53,7 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
 @property (nonatomic) BOOL showSearchBarInitially;
 @property (nonatomic) BOOL showSearchBarInitially;
 
 
 /// nil unless showsSearchBar is set to YES.
 /// nil unless showsSearchBar is set to YES.
-/// 
+///
 /// self is used as the default search results updater and delegate.
 /// self is used as the default search results updater and delegate.
 /// The search bar will not dim the background or hide the navigation bar by default.
 /// The search bar will not dim the background or hide the navigation bar by default.
 /// On iOS 11 and up, the search bar will appear in the navigation bar below the title.
 /// On iOS 11 and up, the search bar will appear in the navigation bar below the title.
@@ -61,13 +61,13 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
 /// Used to initialize the search controller. Defaults to nil.
 /// Used to initialize the search controller. Defaults to nil.
 @property (nonatomic) UIViewController *searchResultsController;
 @property (nonatomic) UIViewController *searchResultsController;
 /// Defaults to "Fast"
 /// Defaults to "Fast"
-/// 
+///
 /// Determines how often search bar results will be "debounced."
 /// Determines how often search bar results will be "debounced."
 /// Empty query events are always sent instantly. Query events will
 /// Empty query events are always sent instantly. Query events will
 /// be sent when the user has not changed the query for this interval.
 /// be sent when the user has not changed the query for this interval.
 @property (nonatomic) FLEXDebounceInterval searchBarDebounceInterval;
 @property (nonatomic) FLEXDebounceInterval searchBarDebounceInterval;
 /// Whether the search bar stays at the top of the view while scrolling.
 /// Whether the search bar stays at the top of the view while scrolling.
-/// 
+///
 /// Calls into self.navigationItem.hidesSearchBarWhenScrolling.
 /// Calls into self.navigationItem.hidesSearchBarWhenScrolling.
 /// Do not change self.navigationItem.hidesSearchBarWhenScrolling directly,
 /// Do not change self.navigationItem.hidesSearchBarWhenScrolling directly,
 /// or it will not be respsected. Use this instead.
 /// or it will not be respsected. Use this instead.
@@ -75,7 +75,7 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
 @property (nonatomic) BOOL pinSearchBar;
 @property (nonatomic) BOOL pinSearchBar;
 /// By default, we will show the search bar's cancel button when 
 /// By default, we will show the search bar's cancel button when 
 /// search becomes active and hide it when search is dismissed.
 /// search becomes active and hide it when search is dismissed.
-/// 
+///
 /// Do not set the showsCancelButton property on the searchController's
 /// Do not set the showsCancelButton property on the searchController's
 /// searchBar manually. Set this property after turning on showsSearchBar.
 /// searchBar manually. Set this property after turning on showsSearchBar.
 ///
 ///
@@ -92,8 +92,11 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
 /// If a delegate is set, updateSearchResults: is not called on this view controller. 
 /// If a delegate is set, updateSearchResults: is not called on this view controller. 
 @property (nonatomic, weak    ) id<FLEXSearchResultsUpdating> searchResultsUpdater;
 @property (nonatomic, weak    ) id<FLEXSearchResultsUpdating> searchResultsUpdater;
 
 
+/// self.view.window as a \c FLEXWindow
+@property (nonatomic, readonly) FLEXWindow *window;
+
 /// Subclasses should override to handle search query update events.
 /// Subclasses should override to handle search query update events.
-/// 
+///
 /// searchBarDebounceInterval is used to reduce the frequency at which this method is called.
 /// searchBarDebounceInterval is used to reduce the frequency at which this method is called.
 /// This method is also called when the search bar becomes the first responder,
 /// This method is also called when the search bar becomes the first responder,
 /// and when the selected search bar scope index changes.
 /// and when the selected search bar scope index changes.

+ 4 - 0
Classes/Core/Controllers/FLEXTableViewController.m

@@ -60,6 +60,10 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
     return self;
     return self;
 }
 }
 
 
+- (FLEXWindow *)window {
+    return (id)self.view.window;
+}
+
 - (void)setShowsSearchBar:(BOOL)showsSearchBar {
 - (void)setShowsSearchBar:(BOOL)showsSearchBar {
     if (_showsSearchBar == showsSearchBar) return;
     if (_showsSearchBar == showsSearchBar) return;
     _showsSearchBar = showsSearchBar;
     _showsSearchBar = showsSearchBar;

+ 13 - 14
Classes/ExplorerInterface/FLEXExplorerViewController.m

@@ -10,6 +10,7 @@
 #import "FLEXExplorerToolbar.h"
 #import "FLEXExplorerToolbar.h"
 #import "FLEXToolbarItem.h"
 #import "FLEXToolbarItem.h"
 #import "FLEXUtility.h"
 #import "FLEXUtility.h"
+#import "FLEXWindow.h"
 #import "FLEXNavigationController.h"
 #import "FLEXNavigationController.h"
 #import "FLEXHierarchyViewController.h"
 #import "FLEXHierarchyViewController.h"
 #import "FLEXGlobalsTableViewController.h"
 #import "FLEXGlobalsTableViewController.h"
@@ -57,10 +58,8 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 /// A colored transparent overlay to indicate that the view is selected.
 /// A colored transparent overlay to indicate that the view is selected.
 @property (nonatomic) UIView *selectedViewOverlay;
 @property (nonatomic) UIView *selectedViewOverlay;
 
 
-/// Tracked so we can restore the key window after dismissing a modal.
-/// We need to become key after modal presentation so we can correctly capture input.
-/// If we're just showing the toolbar, we want the main app's window to remain key so that we don't interfere with input, status bar, etc.
-@property (nonatomic) UIWindow *previousKeyWindow;
+/// self.view.window as a \c FLEXWindow
+@property (nonatomic, readonly) FLEXWindow *window;
 
 
 /// All views that we're KVOing. Used to help us clean up properly.
 /// All views that we're KVOing. Used to help us clean up properly.
 @property (nonatomic) NSMutableSet<UIView *> *observedViews;
 @property (nonatomic) NSMutableSet<UIView *> *observedViews;
@@ -129,8 +128,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 
 
 - (UIViewController *)viewControllerForRotationAndOrientation
 - (UIViewController *)viewControllerForRotationAndOrientation
 {
 {
-    UIWindow *window = self.previousKeyWindow ?: [UIApplication.sharedApplication keyWindow];
-    UIViewController *viewController = window.rootViewController;
+    UIViewController *viewController = FLEXUtility.appKeyWindow.rootViewController;
     // Obfuscating selector _viewControllerForSupportedInterfaceOrientations
     // Obfuscating selector _viewControllerForSupportedInterfaceOrientations
     NSString *viewControllerSelectorString = [@[@"_vie", @"wContro", @"llerFor", @"Supported", @"Interface", @"Orientations"] componentsJoinedByString:@""];
     NSString *viewControllerSelectorString = [@[@"_vie", @"wContro", @"llerFor", @"Supported", @"Interface", @"Orientations"] componentsJoinedByString:@""];
     SEL viewControllerSelector = NSSelectorFromString(viewControllerSelectorString);
     SEL viewControllerSelector = NSSelectorFromString(viewControllerSelectorString);
@@ -790,10 +788,9 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 
 
 - (void)resignKeyAndDismissViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion
 - (void)resignKeyAndDismissViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion
 {
 {
-    UIWindow *previousKeyWindow = self.previousKeyWindow;
-    self.previousKeyWindow = nil;
-    [previousKeyWindow makeKeyWindow];
-    [previousKeyWindow.rootViewController setNeedsStatusBarAppearanceUpdate];
+    UIWindow *appWindow = self.window.previousKeyWindow;
+    [appWindow makeKeyWindow];
+    [appWindow.rootViewController setNeedsStatusBarAppearanceUpdate];
     
     
     // Restore previous UIMenuController items
     // Restore previous UIMenuController items
     // Back up and replace the UIMenuController items
     // Back up and replace the UIMenuController items
@@ -810,7 +807,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 
 
 - (BOOL)wantsWindowToBecomeKey
 - (BOOL)wantsWindowToBecomeKey
 {
 {
-    return self.previousKeyWindow != nil;
+    return self.window.previousKeyWindow != nil;
 }
 }
 
 
 - (void)toggleToolWithViewControllerProvider:(UINavigationController *(^)(void))future completion:(void(^)(void))completion
 - (void)toggleToolWithViewControllerProvider:(UINavigationController *(^)(void))future completion:(void(^)(void))completion
@@ -822,6 +819,10 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
     }
     }
 }
 }
 
 
+- (FLEXWindow *)window {
+    return (id)self.view.window;
+}
+
 
 
 #pragma mark - Keyboard Shortcut Helpers
 #pragma mark - Keyboard Shortcut Helpers
 
 
@@ -870,9 +871,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 - (void)toggleMenuTool
 - (void)toggleMenuTool
 {
 {
     [self toggleToolWithViewControllerProvider:^UINavigationController *{
     [self toggleToolWithViewControllerProvider:^UINavigationController *{
-        FLEXGlobalsTableViewController *globalsViewController = [FLEXGlobalsTableViewController new];
-        [FLEXGlobalsTableViewController setApplicationWindow:[UIApplication.sharedApplication keyWindow]];
-        return [[FLEXNavigationController alloc] initWithRootViewController:globalsViewController];
+        return [[FLEXNavigationController alloc] initWithRootViewController:[FLEXGlobalsTableViewController new]];
     } completion:nil];
     } completion:nil];
 }
 }
 
 

+ 12 - 7
Classes/ExplorerInterface/FLEXWindow.h

@@ -8,17 +8,22 @@
 
 
 #import <UIKit/UIKit.h>
 #import <UIKit/UIKit.h>
 
 
-@protocol FLEXWindowEventDelegate;
-
-@interface FLEXWindow : UIWindow
+@protocol FLEXWindowEventDelegate <NSObject>
 
 
-@property (nonatomic, weak) id <FLEXWindowEventDelegate> eventDelegate;
+- (BOOL)shouldHandleTouchAtPoint:(CGPoint)pointInWindow;
+- (BOOL)canBecomeKeyWindow;
 
 
 @end
 @end
 
 
-@protocol FLEXWindowEventDelegate <NSObject>
+#pragma mark -
+@interface FLEXWindow : UIWindow
 
 
-- (BOOL)shouldHandleTouchAtPoint:(CGPoint)pointInWindow;
-- (BOOL)canBecomeKeyWindow;
+@property (nonatomic, weak) id <FLEXWindowEventDelegate> eventDelegate;
+
+/// Tracked so we can restore the key window after dismissing a modal.
+/// We need to become key after modal presentation so we can correctly capture input.
+/// If we're just showing the toolbar, we want the main app's window to remain key
+/// so that we don't interfere with input, status bar, etc.
+@property (nonatomic, readonly) UIWindow *previousKeyWindow;
 
 
 @end
 @end

+ 11 - 0
Classes/ExplorerInterface/FLEXWindow.m

@@ -7,6 +7,7 @@
 //
 //
 
 
 #import "FLEXWindow.h"
 #import "FLEXWindow.h"
+#import "FLEXUtility.h"
 #import <objc/runtime.h>
 #import <objc/runtime.h>
 
 
 @implementation FLEXWindow
 @implementation FLEXWindow
@@ -43,6 +44,16 @@
     return [self.eventDelegate canBecomeKeyWindow];
     return [self.eventDelegate canBecomeKeyWindow];
 }
 }
 
 
+- (void)makeKeyWindow {
+    _previousKeyWindow = FLEXUtility.appKeyWindow;
+    [super makeKeyWindow];
+}
+
+- (void)resignKeyWindow {
+    [super resignKeyWindow];
+    _previousKeyWindow = nil;
+}
+
 + (void)initialize
 + (void)initialize
 {
 {
     // This adds a method (superclass override) at runtime which gives us the status bar behavior we want.
     // This adds a method (superclass override) at runtime which gives us the status bar behavior we want.

+ 0 - 4
Classes/GlobalStateExplorers/Globals/FLEXGlobalsTableViewController.h

@@ -25,8 +25,4 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsSectionKind) {
 
 
 @interface FLEXGlobalsTableViewController : FLEXTableViewController
 @interface FLEXGlobalsTableViewController : FLEXTableViewController
 
 
-/// We pretend that one of the app's windows is still the key window, even though the explorer window may have become key.
-/// We want to display debug state about the application, not about this tool.
-+ (void)setApplicationWindow:(UIWindow *)applicationWindow;
-
 @end
 @end

+ 0 - 16
Classes/GlobalStateExplorers/Globals/FLEXGlobalsTableViewController.m

@@ -23,8 +23,6 @@
 #import "FLEXAddressExplorerCoordinator.h"
 #import "FLEXAddressExplorerCoordinator.h"
 #import "FLEXGlobalsSection.h"
 #import "FLEXGlobalsSection.h"
 
 
-static __weak UIWindow *s_applicationWindow = nil;
-
 @interface FLEXGlobalsTableViewController ()
 @interface FLEXGlobalsTableViewController ()
 /// Only displayed sections of the table view; empty sections are purged from this array.
 /// Only displayed sections of the table view; empty sections are purged from this array.
 @property (nonatomic, copy) NSArray<FLEXGlobalsSection *> *sections;
 @property (nonatomic, copy) NSArray<FLEXGlobalsSection *> *sections;
@@ -72,13 +70,6 @@ static __weak UIWindow *s_applicationWindow = nil;
         case FLEXGlobalsRowNetworkHistory:
         case FLEXGlobalsRowNetworkHistory:
             return [FLEXNetworkHistoryTableViewController flex_concreteGlobalsEntry:row];
             return [FLEXNetworkHistoryTableViewController flex_concreteGlobalsEntry:row];
         case FLEXGlobalsRowKeyWindow:
         case FLEXGlobalsRowKeyWindow:
-            return [FLEXGlobalsEntry
-                entryWithNameFuture:^NSString *{
-                    return @"🔑  -[UIApplication keyWindow]";
-                } viewControllerFuture:^UIViewController *{
-                    return [FLEXObjectExplorerFactory explorerViewControllerForObject:s_applicationWindow];
-                }
-            ];
         case FLEXGlobalsRowRootViewController:
         case FLEXGlobalsRowRootViewController:
         case FLEXGlobalsRowProcessInfo:
         case FLEXGlobalsRowProcessInfo:
         case FLEXGlobalsRowAppDelegate:
         case FLEXGlobalsRowAppDelegate:
@@ -140,13 +131,6 @@ static __weak UIWindow *s_applicationWindow = nil;
     return sections;
     return sections;
 }
 }
 
 
-#pragma mark - Public
-
-+ (void)setApplicationWindow:(UIWindow *)applicationWindow
-{
-    s_applicationWindow = applicationWindow;
-}
-
 #pragma mark - UIViewController
 #pragma mark - UIViewController
 
 
 - (void)viewDidLoad
 - (void)viewDidLoad

+ 1 - 1
Classes/Manager/FLEXManager+Extensibility.m

@@ -183,7 +183,7 @@
 }
 }
 
 
 - (UIScrollView *)firstScrollView {
 - (UIScrollView *)firstScrollView {
-    NSMutableArray<UIView *> *views = [UIApplication.sharedApplication.keyWindow.subviews mutableCopy];
+    NSMutableArray<UIView *> *views = FLEXUtility.appKeyWindow.subviews.copy;
     UIScrollView *scrollView = nil;
     UIScrollView *scrollView = nil;
     while (views.count > 0) {
     while (views.count > 0) {
         UIView *view = views.firstObject;
         UIView *view = views.firstObject;

+ 9 - 3
Classes/ObjectExplorers/FLEXObjectExplorerFactory.m

@@ -88,13 +88,15 @@ static NSMutableDictionary<Class, Class> *classesToRegisteredSections = nil;
 {
 {
     switch (row) {
     switch (row) {
         case FLEXGlobalsRowAppDelegate:
         case FLEXGlobalsRowAppDelegate:
-            return @"👉  App delegate";
+            return @"🎟  App Delegate";
+        case FLEXGlobalsRowKeyWindow:
+            return @"🔑  Key Window";
         case FLEXGlobalsRowRootViewController:
         case FLEXGlobalsRowRootViewController:
-            return @"🌴  Root view controller";
+            return @"🌴  Root View Controller";
         case FLEXGlobalsRowProcessInfo:
         case FLEXGlobalsRowProcessInfo:
             return @"🚦  NSProcessInfo.processInfo";
             return @"🚦  NSProcessInfo.processInfo";
         case FLEXGlobalsRowUserDefaults:
         case FLEXGlobalsRowUserDefaults:
-            return @"💾  Preferences (NSUserDefaults)";
+            return @"💾  Preferences";
         case FLEXGlobalsRowMainBundle:
         case FLEXGlobalsRowMainBundle:
             return @"📦  NSBundle.mainBundle";
             return @"📦  NSBundle.mainBundle";
         case FLEXGlobalsRowApplication:
         case FLEXGlobalsRowApplication:
@@ -130,6 +132,10 @@ static NSMutableDictionary<Class, Class> *classesToRegisteredSections = nil;
             return [self explorerViewControllerForObject:UIDevice.currentDevice];
             return [self explorerViewControllerForObject:UIDevice.currentDevice];
         case FLEXGlobalsRowPasteboard:
         case FLEXGlobalsRowPasteboard:
             return [self explorerViewControllerForObject:UIPasteboard.generalPasteboard];
             return [self explorerViewControllerForObject:UIPasteboard.generalPasteboard];
+        case FLEXGlobalsRowKeyWindow:
+            return [FLEXObjectExplorerFactory
+                explorerViewControllerForObject:FLEXUtility.appKeyWindow
+            ];
         case FLEXGlobalsRowRootViewController: {
         case FLEXGlobalsRowRootViewController: {
             id<UIApplicationDelegate> delegate = UIApplication.sharedApplication.delegate;
             id<UIApplicationDelegate> delegate = UIApplication.sharedApplication.delegate;
             if ([delegate respondsToSelector:@selector(window)]) {
             if ([delegate respondsToSelector:@selector(window)]) {