Преглед изворни кода

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 година
родитељ
комит
239afdbd7c

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

@@ -7,7 +7,7 @@
 //
 
 #import <UIKit/UIKit.h>
-@class FLEXScopeCarousel;
+@class FLEXScopeCarousel, FLEXWindow;
 
 typedef CGFloat FLEXDebounceInterval;
 /// No delay, all events delivered
@@ -29,7 +29,7 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
 >
 
 /// A grouped table view. Inset on iOS 13.
-/// 
+///
 /// Simply calls into initWithStyle:
 - (id)init;
 
@@ -43,7 +43,7 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
 @property (nonatomic) FLEXScopeCarousel *carousel;
 
 /// Defaults to NO.
-/// 
+///
 /// Setting this to YES will initialize searchController and the view.
 @property (nonatomic) BOOL showsSearchBar;
 /// Defaults to NO.
@@ -53,7 +53,7 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
 @property (nonatomic) BOOL showSearchBarInitially;
 
 /// nil unless showsSearchBar is set to YES.
-/// 
+///
 /// 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.
 /// 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.
 @property (nonatomic) UIViewController *searchResultsController;
 /// Defaults to "Fast"
-/// 
+///
 /// Determines how often search bar results will be "debounced."
 /// Empty query events are always sent instantly. Query events will
 /// be sent when the user has not changed the query for this interval.
 @property (nonatomic) FLEXDebounceInterval searchBarDebounceInterval;
 /// Whether the search bar stays at the top of the view while scrolling.
-/// 
+///
 /// Calls into self.navigationItem.hidesSearchBarWhenScrolling.
 /// Do not change self.navigationItem.hidesSearchBarWhenScrolling directly,
 /// or it will not be respsected. Use this instead.
@@ -75,7 +75,7 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
 @property (nonatomic) BOOL pinSearchBar;
 /// By default, we will show the search bar's cancel button when 
 /// search becomes active and hide it when search is dismissed.
-/// 
+///
 /// Do not set the showsCancelButton property on the searchController's
 /// 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. 
 @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.
-/// 
+///
 /// 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,
 /// 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;
 }
 
+- (FLEXWindow *)window {
+    return (id)self.view.window;
+}
+
 - (void)setShowsSearchBar:(BOOL)showsSearchBar {
     if (_showsSearchBar == showsSearchBar) return;
     _showsSearchBar = showsSearchBar;

+ 13 - 14
Classes/ExplorerInterface/FLEXExplorerViewController.m

@@ -10,6 +10,7 @@
 #import "FLEXExplorerToolbar.h"
 #import "FLEXToolbarItem.h"
 #import "FLEXUtility.h"
+#import "FLEXWindow.h"
 #import "FLEXNavigationController.h"
 #import "FLEXHierarchyViewController.h"
 #import "FLEXGlobalsTableViewController.h"
@@ -57,10 +58,8 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 /// A colored transparent overlay to indicate that the view is selected.
 @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.
 @property (nonatomic) NSMutableSet<UIView *> *observedViews;
@@ -129,8 +128,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 
 - (UIViewController *)viewControllerForRotationAndOrientation
 {
-    UIWindow *window = self.previousKeyWindow ?: [UIApplication.sharedApplication keyWindow];
-    UIViewController *viewController = window.rootViewController;
+    UIViewController *viewController = FLEXUtility.appKeyWindow.rootViewController;
     // Obfuscating selector _viewControllerForSupportedInterfaceOrientations
     NSString *viewControllerSelectorString = [@[@"_vie", @"wContro", @"llerFor", @"Supported", @"Interface", @"Orientations"] componentsJoinedByString:@""];
     SEL viewControllerSelector = NSSelectorFromString(viewControllerSelectorString);
@@ -790,10 +788,9 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 
 - (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
     // Back up and replace the UIMenuController items
@@ -810,7 +807,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 
 - (BOOL)wantsWindowToBecomeKey
 {
-    return self.previousKeyWindow != nil;
+    return self.window.previousKeyWindow != nil;
 }
 
 - (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
 
@@ -870,9 +871,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 - (void)toggleMenuTool
 {
     [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];
 }
 

+ 12 - 7
Classes/ExplorerInterface/FLEXWindow.h

@@ -8,17 +8,22 @@
 
 #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
 
-@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

+ 11 - 0
Classes/ExplorerInterface/FLEXWindow.m

@@ -7,6 +7,7 @@
 //
 
 #import "FLEXWindow.h"
+#import "FLEXUtility.h"
 #import <objc/runtime.h>
 
 @implementation FLEXWindow
@@ -43,6 +44,16 @@
     return [self.eventDelegate canBecomeKeyWindow];
 }
 
+- (void)makeKeyWindow {
+    _previousKeyWindow = FLEXUtility.appKeyWindow;
+    [super makeKeyWindow];
+}
+
+- (void)resignKeyWindow {
+    [super resignKeyWindow];
+    _previousKeyWindow = nil;
+}
+
 + (void)initialize
 {
     // 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
 
-/// 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

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

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

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

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

+ 9 - 3
Classes/ObjectExplorers/FLEXObjectExplorerFactory.m

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