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

Upgrades to the globals screen

- Refactor FLEXGlobalsTableViewController
- Add search to FLEXGlobalsTableViewController
- FLEXGlobalsTableViewControllerEntry → FLEXGlobalsEntry
- Add FLEXTableViewSection to help with new search code
- Add `hidesSearchBarInitially` to FLEXTableViewController
Tanner Bennett лет назад: 7
Родитель
Сommit
eb4160636f
27 измененных файлов с 295 добавлено и 112 удалено
  1. 5 0
      Classes/Core/FLEXTableViewController.h
  2. 2 2
      Classes/Core/FLEXTableViewController.m
  3. 39 0
      Classes/Core/FLEXTableViewSection.h
  4. 49 0
      Classes/Core/FLEXTableViewSection.m
  5. 2 2
      Classes/GlobalStateExplorers/FLEXAddressExplorerCoordinator.h
  6. 1 1
      Classes/GlobalStateExplorers/FLEXAddressExplorerCoordinator.m
  7. 2 2
      Classes/GlobalStateExplorers/FLEXClassesTableViewController.h
  8. 1 1
      Classes/GlobalStateExplorers/FLEXClassesTableViewController.m
  9. 2 2
      Classes/GlobalStateExplorers/FLEXCookiesTableViewController.h
  10. 1 1
      Classes/GlobalStateExplorers/FLEXCookiesTableViewController.m
  11. 2 2
      Classes/GlobalStateExplorers/FLEXLibrariesTableViewController.h
  12. 1 1
      Classes/GlobalStateExplorers/FLEXLibrariesTableViewController.m
  13. 2 2
      Classes/GlobalStateExplorers/FLEXLiveObjectsTableViewController.h
  14. 1 1
      Classes/GlobalStateExplorers/FLEXLiveObjectsTableViewController.m
  15. 2 2
      Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserTableViewController.h
  16. 1 1
      Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserTableViewController.m
  17. 13 12
      Classes/ObjectExplorers/Controllers/FLEXGlobalsTableViewControllerEntry.h
  18. 21 13
      Classes/ObjectExplorers/Controllers/FLEXGlobalsTableViewControllerEntry.m
  19. 0 0
      Classes/GlobalStateExplorers/Globals/FLEXGlobalsTableViewController.h
  20. 109 44
      Classes/GlobalStateExplorers/FLEXGlobalsTableViewController.m
  21. 2 2
      Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogTableViewController.h
  22. 1 1
      Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogTableViewController.m
  23. 3 3
      Classes/Manager/FLEXManager+Private.h
  24. 4 4
      Classes/Manager/FLEXManager.m
  25. 2 2
      Classes/Network/FLEXNetworkHistoryTableViewController.h
  26. 1 1
      Classes/Network/FLEXNetworkHistoryTableViewController.m
  27. 26 10
      FLEX.xcodeproj/project.pbxproj

+ 5 - 0
Classes/Core/FLEXTableViewController.h

@@ -29,6 +29,11 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
 /// 
 /// Setting this to YES will initialize searchController.
 @property (nonatomic) BOOL showsSearchBar;
+/// Defaults to NO.
+///
+/// Setting this to YES will make the search bar appear whenever the view appears.
+/// Otherwise, iOS will only show the search bar when you scroll up.
+@property (nonatomic) BOOL hideSearchBarInitially;
 
 /// nil unless showsSearchBar is set to YES.
 /// 

+ 2 - 2
Classes/Core/FLEXTableViewController.m

@@ -112,7 +112,7 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
     [super viewWillAppear:animated];
     
     // Make the search bar re-appear instead of hiding
-    if (@available(iOS 11.0, *)) {
+    if (@available(iOS 11.0, *)) if (!self.hideSearchBarInitially) {
         self.navigationItem.hidesSearchBarWhenScrolling = NO;
     }
 }
@@ -122,7 +122,7 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
     
     // Allow scrolling to collapse the search bar,
     // only if we don't want it pinned
-    if (@available(iOS 11.0, *)) {
+    if (@available(iOS 11.0, *)) if (!self.hideSearchBarInitially) {
         self.navigationItem.hidesSearchBarWhenScrolling = !self.pinSearchBar;
     }
 }

+ 39 - 0
Classes/Core/FLEXTableViewSection.h

@@ -0,0 +1,39 @@
+//
+//  FLEXTableViewSection.h
+//  FLEX
+//
+//  Created by Tanner Bennett on 7/11/19.
+//  Copyright © 2019 Flipboard. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// A protocol for arbitrary case-insensitive pattern matching
+@protocol FLEXPatternMatching <NSObject>
+/// @return YES if the receiver matches the query, case-insensitive
+- (BOOL)matches:(NSString *)query;
+@end
+
+@interface FLEXTableViewSection<__covariant ObjectType> : NSObject
+
++ (instancetype)section:(NSInteger)section title:(NSString *)title rows:(NSArray<ObjectType<FLEXPatternMatching>> *)rows;
+
+@property (nonatomic, readonly) NSInteger section;
+@property (nonatomic, readonly) NSString *title;
+@property (nonatomic, readonly) NSArray<ObjectType<FLEXPatternMatching>> *rows;
+
+@property (nonatomic, readonly) NSInteger count;
+
+/// @return A new section containing only rows that match the string,
+/// or nil if the section was empty and no rows matched the string.
+- (nullable instancetype)newSectionWithRowsMatchingQuery:(NSString *)query;
+
+@end
+
+@interface FLEXTableViewSection<__covariant ObjectType> (Subscripting)
+- (ObjectType)objectAtIndexedSubscript:(NSUInteger)idx;
+@end
+
+NS_ASSUME_NONNULL_END

+ 49 - 0
Classes/Core/FLEXTableViewSection.m

@@ -0,0 +1,49 @@
+//
+//  FLEXTableViewSection.m
+//  FLEX
+//
+//  Created by Tanner Bennett on 7/11/19.
+//  Copyright © 2019 Flipboard. All rights reserved.
+//
+
+#import "FLEXTableViewSection.h"
+
+@implementation FLEXTableViewSection
+
++ (instancetype)section:(NSInteger)section title:(NSString *)title rows:(NSArray *)rows {
+    FLEXTableViewSection *s = [self new];
+    s->_section = section;
+    s->_title = title;
+    s->_rows = rows.copy;
+
+    return s;
+}
+
+- (instancetype)newSectionWithRowsMatchingQuery:(NSString *)query {
+    // Find rows containing the search string
+    NSPredicate *containsString = [NSPredicate predicateWithBlock:^BOOL(id<FLEXPatternMatching> obj, NSDictionary *bindings) {
+        return [obj matches:query];
+    }];
+    NSArray *filteredRows = [self.rows filteredArrayUsingPredicate:containsString];
+    
+    // Only return new section if not empty
+    if (filteredRows.count) {
+        return [[self class] section:self.section title:self.title rows:filteredRows];
+    }
+    
+    return nil;
+}
+
+- (NSInteger)count {
+    return self.rows.count;
+}
+
+@end
+
+@implementation FLEXTableViewSection (Subscripting)
+
+- (id)objectAtIndexedSubscript:(NSUInteger)idx {
+    return self.rows[idx];
+}
+
+@end

+ 2 - 2
Classes/GlobalStateExplorers/FLEXAddressExplorerCoordinator.h

@@ -6,8 +6,8 @@
 //  Copyright © 2019 Flipboard. All rights reserved.
 //
 
-#import "FLEXGlobalsTableViewControllerEntry.h"
+#import "FLEXGlobalsEntry.h"
 
-@interface FLEXAddressExplorerCoordinator : NSObject <FLEXGlobalsTableViewControllerEntry>
+@interface FLEXAddressExplorerCoordinator : NSObject <FLEXGlobalsEntry>
 
 @end

+ 1 - 1
Classes/GlobalStateExplorers/FLEXAddressExplorerCoordinator.m

@@ -20,7 +20,7 @@
 
 @implementation FLEXAddressExplorerCoordinator
 
-#pragma mark - FLEXGlobalsTableViewControllerEntry
+#pragma mark - FLEXGlobalsEntry
 
 + (NSString *)globalsEntryTitle {
     return @"🔎 Address Explorer";

+ 2 - 2
Classes/GlobalStateExplorers/FLEXClassesTableViewController.h

@@ -7,9 +7,9 @@
 //
 
 #import "FLEXTableViewController.h"
-#import "FLEXGlobalsTableViewControllerEntry.h"
+#import "FLEXGlobalsEntry.h"
 
-@interface FLEXClassesTableViewController : FLEXTableViewController <FLEXGlobalsTableViewControllerEntry>
+@interface FLEXClassesTableViewController : FLEXTableViewController <FLEXGlobalsEntry>
 
 @property (nonatomic, copy) NSString *binaryImageName;
 

+ 1 - 1
Classes/GlobalStateExplorers/FLEXClassesTableViewController.m

@@ -68,7 +68,7 @@
 }
 
 
-#pragma mark - FLEXGlobalsTableViewControllerEntry
+#pragma mark - FLEXGlobalsEntry
 
 + (NSString *)globalsEntryTitle {
     return [NSString stringWithFormat:@"📕  %@ Classes", [FLEXUtility applicationName]];

+ 2 - 2
Classes/GlobalStateExplorers/FLEXCookiesTableViewController.h

@@ -6,8 +6,8 @@
 //  Copyright © 2015 Flipboard. All rights reserved.
 //
 
-#import "FLEXGlobalsTableViewControllerEntry.h"
+#import "FLEXGlobalsEntry.h"
 
-@interface FLEXCookiesTableViewController : UITableViewController <FLEXGlobalsTableViewControllerEntry>
+@interface FLEXCookiesTableViewController : UITableViewController <FLEXGlobalsEntry>
 
 @end

+ 1 - 1
Classes/GlobalStateExplorers/FLEXCookiesTableViewController.m

@@ -68,7 +68,7 @@
     [self.navigationController pushViewController:cookieViewController animated:YES];
 }
 
-#pragma mark - FLEXGlobalsTableViewControllerEntry
+#pragma mark - FLEXGlobalsEntry
 
 + (NSString *)globalsEntryTitle {
     return @"🍪  Cookies";

+ 2 - 2
Classes/GlobalStateExplorers/FLEXLibrariesTableViewController.h

@@ -7,8 +7,8 @@
 //
 
 #import "FLEXTableViewController.h"
-#import "FLEXGlobalsTableViewControllerEntry.h"
+#import "FLEXGlobalsEntry.h"
 
-@interface FLEXLibrariesTableViewController : FLEXTableViewController <FLEXGlobalsTableViewControllerEntry>
+@interface FLEXLibrariesTableViewController : FLEXTableViewController <FLEXGlobalsEntry>
 
 @end

+ 1 - 1
Classes/GlobalStateExplorers/FLEXLibrariesTableViewController.m

@@ -40,7 +40,7 @@
 }
 
 
-#pragma mark - FLEXGlobalsTableViewControllerEntry
+#pragma mark - FLEXGlobalsEntry
 
 + (NSString *)globalsEntryTitle {
     return @"📚  System Libraries";

+ 2 - 2
Classes/GlobalStateExplorers/FLEXLiveObjectsTableViewController.h

@@ -7,8 +7,8 @@
 //
 
 #import "FLEXTableViewController.h"
-#import "FLEXGlobalsTableViewControllerEntry.h"
+#import "FLEXGlobalsEntry.h"
 
-@interface FLEXLiveObjectsTableViewController : FLEXTableViewController <FLEXGlobalsTableViewControllerEntry>
+@interface FLEXLiveObjectsTableViewController : FLEXTableViewController <FLEXGlobalsEntry>
 
 @end

+ 1 - 1
Classes/GlobalStateExplorers/FLEXLiveObjectsTableViewController.m

@@ -127,7 +127,7 @@ static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
 }
 
 
-#pragma mark - FLEXGlobalsTableViewControllerEntry
+#pragma mark - FLEXGlobalsEntry
 
 + (NSString *)globalsEntryTitle {
     return @"💩  Heap Objects";

+ 2 - 2
Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserTableViewController.h

@@ -7,10 +7,10 @@
 //
 
 #import "FLEXTableViewController.h"
-#import "FLEXGlobalsTableViewControllerEntry.h"
+#import "FLEXGlobalsEntry.h"
 #import "FLEXFileBrowserSearchOperation.h"
 
-@interface FLEXFileBrowserTableViewController : FLEXTableViewController <FLEXGlobalsTableViewControllerEntry>
+@interface FLEXFileBrowserTableViewController : FLEXTableViewController <FLEXGlobalsEntry>
 
 - (id)initWithPath:(NSString *)path;
 

+ 1 - 1
Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserTableViewController.m

@@ -86,7 +86,7 @@
     self.searchBarDebounceInterval = kFLEXDebounceForAsyncSearch;
 }
 
-#pragma mark - FLEXGlobalsTableViewControllerEntry
+#pragma mark - FLEXGlobalsEntry
 
 + (NSString *)globalsEntryTitle {
     return @"📁  File Browser";

+ 13 - 12
Classes/ObjectExplorers/Controllers/FLEXGlobalsTableViewControllerEntry.h

@@ -1,5 +1,5 @@
 //
-//  FLEXGlobalsTableViewControllerEntry.h
+//  FLEXGlobalsEntry.h
 //  FLEX
 //
 //  Created by Javier Soto on 7/26/14.
@@ -7,9 +7,10 @@
 //
 
 #import <UIKit/UIKit.h>
+#import "FLEXTableViewSection.h"
 @class FLEXGlobalsTableViewController;
 
-typedef NSString *(^FLEXGlobalsTableViewControllerEntryNameFuture)(void);
+typedef NSString *(^FLEXGlobalsEntryNameFuture)(void);
 /// Simply return a view controller to be pushed on the navigation stack
 typedef UIViewController *(^FLEXGlobalsTableViewControllerViewControllerFuture)(void);
 /// Do something like present an alert, then use the host
@@ -22,7 +23,7 @@ typedef void (^FLEXGlobalsTableViewControllerRowAction)(FLEXGlobalsTableViewCont
 /// Previously, the concrete entries relied on "futures" for the view controller and title.
 /// With this protocol, the conforming class itself can act as a future, since the methods
 /// will not be invoked until the title and view controller / row action are needed.
-@protocol FLEXGlobalsTableViewControllerEntry <NSObject>
+@protocol FLEXGlobalsEntry <NSObject>
 
 + (NSString *)globalsEntryTitle;
 
@@ -34,23 +35,23 @@ typedef void (^FLEXGlobalsTableViewControllerRowAction)(FLEXGlobalsTableViewCont
 
 @end
 
-@interface FLEXGlobalsTableViewControllerEntry : NSObject
+@interface FLEXGlobalsEntry : NSObject <FLEXPatternMatching>
 
-@property (nonatomic, readonly) FLEXGlobalsTableViewControllerEntryNameFuture entryNameFuture;
+@property (nonatomic, readonly) FLEXGlobalsEntryNameFuture entryNameFuture;
 @property (nonatomic, readonly) FLEXGlobalsTableViewControllerViewControllerFuture viewControllerFuture;
 @property (nonatomic, readonly) FLEXGlobalsTableViewControllerRowAction rowAction;
 
-+ (instancetype)entryWithEntry:(Class<FLEXGlobalsTableViewControllerEntry>)entry;
-+ (instancetype)entryWithNameFuture:(FLEXGlobalsTableViewControllerEntryNameFuture)nameFuture viewControllerFuture:(FLEXGlobalsTableViewControllerViewControllerFuture)viewControllerFuture;
-+ (instancetype)entryWithNameFuture:(FLEXGlobalsTableViewControllerEntryNameFuture)nameFuture action:(FLEXGlobalsTableViewControllerRowAction)rowSelectedAction;
++ (instancetype)entryWithEntry:(Class<FLEXGlobalsEntry>)entry;
++ (instancetype)entryWithNameFuture:(FLEXGlobalsEntryNameFuture)nameFuture viewControllerFuture:(FLEXGlobalsTableViewControllerViewControllerFuture)viewControllerFuture;
++ (instancetype)entryWithNameFuture:(FLEXGlobalsEntryNameFuture)nameFuture action:(FLEXGlobalsTableViewControllerRowAction)rowSelectedAction;
 
 @end
 
 
-@interface NSObject (FLEXGlobalsTableViewControllerEntry)
+@interface NSObject (FLEXGlobalsEntry)
 
-/// @return The result of passing self to +[FLEXGlobalsTableViewControllerEntry entryWithEntry:]
-/// if the class conforms to FLEXGlobalsTableViewControllerEntry, else, nil.
-+ (FLEXGlobalsTableViewControllerEntry *)flex_concreteGlobalsEntry;
+/// @return The result of passing self to +[FLEXGlobalsEntry entryWithEntry:]
+/// if the class conforms to FLEXGlobalsEntry, else, nil.
++ (FLEXGlobalsEntry *)flex_concreteGlobalsEntry;
 
 @end

+ 21 - 13
Classes/ObjectExplorers/Controllers/FLEXGlobalsTableViewControllerEntry.m

@@ -1,16 +1,16 @@
 //
-//  FLEXGlobalsTableViewControllerEntry.m
+//  FLEXGlobalsEntry.m
 //  FLEX
 //
 //  Created by Javier Soto on 7/26/14.
 //  Copyright (c) 2014 f. All rights reserved.
 //
 
-#import "FLEXGlobalsTableViewControllerEntry.h"
+#import "FLEXGlobalsEntry.h"
 
-@implementation FLEXGlobalsTableViewControllerEntry
+@implementation FLEXGlobalsEntry
 
-+ (instancetype)entryWithEntry:(Class<FLEXGlobalsTableViewControllerEntry>)cls
++ (instancetype)entryWithEntry:(Class<FLEXGlobalsEntry>)cls
 {
     NSParameterAssert(cls);
     NSParameterAssert(
@@ -18,7 +18,7 @@
         [cls respondsToSelector:@selector(globalsEntryRowAction)]
     );
 
-    FLEXGlobalsTableViewControllerEntry *entry = [self new];
+    FLEXGlobalsEntry *entry = [self new];
     entry->_entryNameFuture = ^{ return [cls globalsEntryTitle]; };
 
     if ([cls respondsToSelector:@selector(globalsEntryViewController)]) {
@@ -30,40 +30,48 @@
     return entry;
 }
 
-+ (instancetype)entryWithNameFuture:(FLEXGlobalsTableViewControllerEntryNameFuture)nameFuture
++ (instancetype)entryWithNameFuture:(FLEXGlobalsEntryNameFuture)nameFuture
                viewControllerFuture:(FLEXGlobalsTableViewControllerViewControllerFuture)viewControllerFuture
 {
     NSParameterAssert(nameFuture);
     NSParameterAssert(viewControllerFuture);
 
-    FLEXGlobalsTableViewControllerEntry *entry = [self new];
+    FLEXGlobalsEntry *entry = [self new];
     entry->_entryNameFuture = [nameFuture copy];
     entry->_viewControllerFuture = [viewControllerFuture copy];
 
     return entry;
 }
 
-+ (instancetype)entryWithNameFuture:(FLEXGlobalsTableViewControllerEntryNameFuture)nameFuture
++ (instancetype)entryWithNameFuture:(FLEXGlobalsEntryNameFuture)nameFuture
                              action:(FLEXGlobalsTableViewControllerRowAction)rowSelectedAction
 {
     NSParameterAssert(nameFuture);
     NSParameterAssert(rowSelectedAction);
 
-    FLEXGlobalsTableViewControllerEntry *entry = [self new];
+    FLEXGlobalsEntry *entry = [self new];
     entry->_entryNameFuture = [nameFuture copy];
     entry->_rowAction = [rowSelectedAction copy];
 
     return entry;
 }
 
+#pragma mark FLEXPatternMatching
+
+- (BOOL)matches:(NSString *)query
+{
+    return [self.entryNameFuture() localizedCaseInsensitiveContainsString:query];
+}
+
 @end
 
+#pragma mark - flex_concreteGlobalsEntry
 
-@implementation NSObject (FLEXGlobalsTableViewControllerEntry)
+@implementation NSObject (FLEXGlobalsEntry)
 
-+ (FLEXGlobalsTableViewControllerEntry *)flex_concreteGlobalsEntry {
-    if ([self conformsToProtocol:@protocol(FLEXGlobalsTableViewControllerEntry)]) {
-        return [FLEXGlobalsTableViewControllerEntry entryWithEntry:self];
++ (FLEXGlobalsEntry *)flex_concreteGlobalsEntry {
+    if ([self conformsToProtocol:@protocol(FLEXGlobalsEntry)]) {
+        return [FLEXGlobalsEntry entryWithEntry:self];
     }
 
     return nil;

Classes/GlobalStateExplorers/FLEXGlobalsTableViewController.h → Classes/GlobalStateExplorers/Globals/FLEXGlobalsTableViewController.h


+ 109 - 44
Classes/GlobalStateExplorers/FLEXGlobalsTableViewController.m

@@ -16,11 +16,12 @@
 #import "FLEXLiveObjectsTableViewController.h"
 #import "FLEXFileBrowserTableViewController.h"
 #import "FLEXCookiesTableViewController.h"
-#import "FLEXGlobalsTableViewControllerEntry.h"
+#import "FLEXGlobalsEntry.h"
 #import "FLEXManager+Private.h"
 #import "FLEXSystemLogTableViewController.h"
 #import "FLEXNetworkHistoryTableViewController.h"
 #import "FLEXAddressExplorerCoordinator.h"
+#import "FLEXTableViewSection.h"
 
 static __weak UIWindow *s_applicationWindow = nil;
 
@@ -60,7 +61,8 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
 
 @interface FLEXGlobalsTableViewController ()
 
-@property (nonatomic, readonly) NSArray<NSArray<FLEXGlobalsTableViewControllerEntry *> *> *sections;
+@property (nonatomic, readonly) NSArray<FLEXTableViewSection<FLEXGlobalsEntry *> *> *sections;
+@property (nonatomic, copy) NSArray<FLEXTableViewSection<FLEXGlobalsEntry *> *> *filteredSections;
 
 @end
 
@@ -83,7 +85,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
     }
 }
 
-+ (FLEXGlobalsTableViewControllerEntry *)globalsEntryForRow:(FLEXGlobalsRow)row
++ (FLEXGlobalsEntry *)globalsEntryForRow:(FLEXGlobalsRow)row
 {
     switch (row) {
         case FLEXGlobalsRowAppClasses:
@@ -103,7 +105,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
         case FLEXGlobalsRowNetworkHistory:
             return [FLEXNetworkHistoryTableViewController flex_concreteGlobalsEntry];
         case FLEXGlobalsRowAppDelegate:
-            return [FLEXGlobalsTableViewControllerEntry
+            return [FLEXGlobalsEntry
                 entryWithNameFuture:^NSString *{
                     return [NSString stringWithFormat:@"👉  %@", [[UIApplication sharedApplication].delegate class]];
                 } viewControllerFuture:^UIViewController *{
@@ -112,7 +114,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
                 }
             ];
         case FLEXGlobalsRowRootViewController:
-            return [FLEXGlobalsTableViewControllerEntry
+            return [FLEXGlobalsEntry
                 entryWithNameFuture:^NSString *{
                     return [NSString stringWithFormat:@"🌴  %@", [s_applicationWindow.rootViewController class]];
                 } viewControllerFuture:^UIViewController *{
@@ -121,7 +123,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
                 }
             ];
         case FLEXGlobalsRowUserDefaults:
-            return [FLEXGlobalsTableViewControllerEntry
+            return [FLEXGlobalsEntry
                 entryWithNameFuture:^NSString *{
                     return @"🚶  +[NSUserDefaults standardUserDefaults]";
                 } viewControllerFuture:^UIViewController *{
@@ -130,7 +132,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
                 }
             ];
         case FLEXGlobalsRowMainBundle:
-            return [FLEXGlobalsTableViewControllerEntry
+            return [FLEXGlobalsEntry
                 entryWithNameFuture:^NSString *{
                     return @"📦  +[NSBundle mainBundle]";
                 } viewControllerFuture:^UIViewController *{
@@ -139,7 +141,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
                 }
             ];
         case FLEXGlobalsRowApplication:
-            return [FLEXGlobalsTableViewControllerEntry
+            return [FLEXGlobalsEntry
                 entryWithNameFuture:^NSString *{
                     return @"💾  +[UIApplication sharedApplication]";
                 } viewControllerFuture:^UIViewController *{
@@ -148,7 +150,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
                 }
             ];
         case FLEXGlobalsRowKeyWindow:
-            return [FLEXGlobalsTableViewControllerEntry
+            return [FLEXGlobalsEntry
                 entryWithNameFuture:^NSString *{
                     return @"🔑  -[UIApplication keyWindow]";
                 } viewControllerFuture:^UIViewController *{
@@ -156,7 +158,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
                 }
             ];
         case FLEXGlobalsRowMainScreen:
-            return [FLEXGlobalsTableViewControllerEntry
+            return [FLEXGlobalsEntry
                 entryWithNameFuture:^NSString *{
                     return @"💻  +[UIScreen mainScreen]";
                 } viewControllerFuture:^UIViewController *{
@@ -166,7 +168,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
             ];
 
         case FLEXGlobalsRowCurrentDevice:
-            return [FLEXGlobalsTableViewControllerEntry
+            return [FLEXGlobalsEntry
                 entryWithNameFuture:^NSString *{
                     return @"📱  +[UIDevice currentDevice]";
                 } viewControllerFuture:^UIViewController *{
@@ -180,31 +182,45 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
     }
 }
 
-+ (NSArray<NSArray<FLEXGlobalsTableViewControllerEntry *> *> *)defaultGlobalSections
++ (NSArray<FLEXTableViewSection<FLEXGlobalsEntry *> *> *)defaultGlobalSections
 {
-    return @[
-        @[ // FLEXGlobalsSectionProcess
-            [self globalsEntryForRow:FLEXGlobalsRowNetworkHistory],
-            [self globalsEntryForRow:FLEXGlobalsRowSystemLog],
-            [self globalsEntryForRow:FLEXGlobalsRowLiveObjects],
-            [self globalsEntryForRow:FLEXGlobalsRowAddressInspector],
-            [self globalsEntryForRow:FLEXGlobalsRowSystemLibraries],
-            [self globalsEntryForRow:FLEXGlobalsRowAppClasses],
-        ],
-        @[ // FLEXGlobalsSectionAppShortcuts
-            [self globalsEntryForRow:FLEXGlobalsRowMainBundle],
-            [self globalsEntryForRow:FLEXGlobalsRowUserDefaults],
-            [self globalsEntryForRow:FLEXGlobalsRowApplication],
-            [self globalsEntryForRow:FLEXGlobalsRowAppDelegate],
-            [self globalsEntryForRow:FLEXGlobalsRowKeyWindow],
-            [self globalsEntryForRow:FLEXGlobalsRowRootViewController],
-            [self globalsEntryForRow:FLEXGlobalsRowCookies],
-        ],
-        @[ // FLEXGlobalsSectionMisc
-            [self globalsEntryForRow:FLEXGlobalsRowMainScreen],
-            [self globalsEntryForRow:FLEXGlobalsRowCurrentDevice],
-        ]
-    ];
+    static NSArray<FLEXTableViewSection<FLEXGlobalsEntry *> *> *sections = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        NSArray *rows = @[
+            @[
+                [self globalsEntryForRow:FLEXGlobalsRowNetworkHistory],
+                [self globalsEntryForRow:FLEXGlobalsRowSystemLog],
+                [self globalsEntryForRow:FLEXGlobalsRowLiveObjects],
+                [self globalsEntryForRow:FLEXGlobalsRowAddressInspector],
+                [self globalsEntryForRow:FLEXGlobalsRowSystemLibraries],
+                [self globalsEntryForRow:FLEXGlobalsRowAppClasses],
+            ],
+            @[ // FLEXGlobalsSectionAppShortcuts
+                [self globalsEntryForRow:FLEXGlobalsRowMainBundle],
+                [self globalsEntryForRow:FLEXGlobalsRowUserDefaults],
+                [self globalsEntryForRow:FLEXGlobalsRowApplication],
+                [self globalsEntryForRow:FLEXGlobalsRowAppDelegate],
+                [self globalsEntryForRow:FLEXGlobalsRowKeyWindow],
+                [self globalsEntryForRow:FLEXGlobalsRowRootViewController],
+                [self globalsEntryForRow:FLEXGlobalsRowCookies],
+            ],
+            @[ // FLEXGlobalsSectionMisc
+                [self globalsEntryForRow:FLEXGlobalsRowMainScreen],
+                [self globalsEntryForRow:FLEXGlobalsRowCurrentDevice],
+            ]
+        ];
+        
+        NSMutableArray *tmp = [NSMutableArray array];
+        for (NSInteger i = 0; i < FLEXGlobalsSectionCount - 1; i++) { // Skip custom
+            NSString *title = [self globalsTitleForSection:i];
+            [tmp addObject:[FLEXTableViewSection section:i title:title rows:rows[i]]];
+        }
+        
+        sections = tmp.copy;
+    });
+    
+    return sections;
 }
 
 #pragma mark - Public
@@ -221,17 +237,50 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
     [super viewDidLoad];
 
     self.title = @"💪  FLEX";
+    self.showsSearchBar = YES;
+    self.hideSearchBarInitially = YES;
+    self.searchBarDebounceInterval = kFLEXDebounceInstant;
 
     // Table view data
     _sections = [[self class] defaultGlobalSections];
     if ([FLEXManager sharedManager].userGlobalEntries.count) {
-        _sections = [_sections arrayByAddingObject:[FLEXManager sharedManager].userGlobalEntries];
+        // Make custom section
+        NSString *title = [[self class] globalsTitleForSection:FLEXGlobalsSectionCustom];
+        FLEXTableViewSection *custom = [FLEXTableViewSection
+            section:FLEXGlobalsSectionCustom
+            title:title
+            rows:[FLEXManager sharedManager].userGlobalEntries
+        ];
+        _sections = [_sections arrayByAddingObject:custom];
     }
 
     // Done button
     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(donePressed:)];
 }
 
+#pragma mark - Search Bar
+
+- (void)updateSearchResults:(NSString *)newText {
+    if (!newText.length) {
+        self.filteredSections = nil;
+        [self.tableView reloadData];
+        return;
+    }
+
+    // Sections are a map of index to rows, since empty sections are omitted
+    NSMutableArray *filteredSections = [NSMutableArray array];
+
+    [self.sections enumerateObjectsUsingBlock:^(FLEXTableViewSection<FLEXGlobalsEntry *> *section, NSUInteger idx, BOOL *stop) {
+        section = [section newSectionWithRowsMatchingQuery:newText];
+        if (section) {
+            [filteredSections addObject:section];
+        }
+    }];
+
+    self.filteredSections = filteredSections.copy;
+    [self.tableView reloadData];
+}
+
 #pragma mark - Misc
 
 - (void)donePressed:(id)sender
@@ -241,15 +290,27 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
 
 #pragma mark - Table Data Helpers
 
-- (FLEXGlobalsTableViewControllerEntry *)globalEntryAtIndexPath:(NSIndexPath *)indexPath
+- (FLEXGlobalsEntry *)globalEntryAtIndexPath:(NSIndexPath *)indexPath
+{
+    if (self.filteredSections) {
+        return self.filteredSections[indexPath.section][indexPath.row];
+    } else {
+        return self.sections[indexPath.section][indexPath.row];
+    }
+}
+
+- (NSString *)titleForSection:(NSInteger)section
 {
-    return self.sections[indexPath.section][indexPath.row];
+    if (self.filteredSections) {
+        return self.filteredSections[section].title;
+    } else {
+        return self.sections[section].title;
+    }
 }
 
 - (NSString *)titleForRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    FLEXGlobalsTableViewControllerEntry *entry = [self globalEntryAtIndexPath:indexPath];
-
+    FLEXGlobalsEntry *entry = [self globalEntryAtIndexPath:indexPath];
     return entry.entryNameFuture();
 }
 
@@ -257,12 +318,16 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
 
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 {
-    return self.sections.count;
+    return self.filteredSections ? self.filteredSections.count : self.sections.count;
 }
 
 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 {
-    return self.sections[section].count;
+    if (self.filteredSections) {
+        return self.filteredSections[section].count;
+    } else {
+        return self.sections[section].count;
+    }
 }
 
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
@@ -282,14 +347,14 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
 
 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
 {
-    return [[self class] globalsTitleForSection:section];
+    return [self titleForSection:section];
 }
 
 #pragma mark - Table View Delegate
 
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    FLEXGlobalsTableViewControllerEntry *entry = [self globalEntryAtIndexPath:indexPath];
+    FLEXGlobalsEntry *entry = [self globalEntryAtIndexPath:indexPath];
     if (entry.viewControllerFuture) {
         [self.navigationController pushViewController:entry.viewControllerFuture() animated:YES];
     } else {

+ 2 - 2
Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogTableViewController.h

@@ -7,8 +7,8 @@
 //
 
 #import "FLEXTableViewController.h"
-#import "FLEXGlobalsTableViewControllerEntry.h"
+#import "FLEXGlobalsEntry.h"
 
-@interface FLEXSystemLogTableViewController : FLEXTableViewController <FLEXGlobalsTableViewControllerEntry>
+@interface FLEXSystemLogTableViewController : FLEXTableViewController <FLEXGlobalsEntry>
 
 @end

+ 1 - 1
Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogTableViewController.m

@@ -116,7 +116,7 @@
     [self presentViewController:settings animated:YES completion:nil];
 }
 
-#pragma mark - FLEXGlobalsTableViewControllerEntry
+#pragma mark - FLEXGlobalsEntry
 
 + (NSString *)globalsEntryTitle {
     return @"⚠️  System Log";

+ 3 - 3
Classes/Manager/FLEXManager+Private.h

@@ -8,12 +8,12 @@
 
 #import "FLEXManager.h"
 
-@class FLEXGlobalsTableViewControllerEntry;
+@class FLEXGlobalsEntry;
 
 @interface FLEXManager ()
 
-/// An array of FLEXGlobalsTableViewControllerEntry objects that have been registered by the user.
-@property (nonatomic, readonly, strong) NSArray<FLEXGlobalsTableViewControllerEntry *> *userGlobalEntries;
+/// An array of FLEXGlobalsEntry objects that have been registered by the user.
+@property (nonatomic, readonly, strong) NSArray<FLEXGlobalsEntry *> *userGlobalEntries;
 
 @property (nonatomic, readonly, strong) NSDictionary<NSString *, FLEXCustomContentViewerFuture> *customContentTypeViewers;
 

+ 4 - 4
Classes/Manager/FLEXManager.m

@@ -9,7 +9,7 @@
 #import "FLEXManager.h"
 #import "FLEXExplorerViewController.h"
 #import "FLEXWindow.h"
-#import "FLEXGlobalsTableViewControllerEntry.h"
+#import "FLEXGlobalsEntry.h"
 #import "FLEXObjectExplorerFactory.h"
 #import "FLEXObjectExplorerViewController.h"
 #import "FLEXNetworkObserver.h"
@@ -24,7 +24,7 @@
 @property (nonatomic, strong) FLEXWindow *explorerWindow;
 @property (nonatomic, strong) FLEXExplorerViewController *explorerViewController;
 
-@property (nonatomic, readonly, strong) NSMutableArray<FLEXGlobalsTableViewControllerEntry *> *userGlobalEntries;
+@property (nonatomic, readonly, strong) NSMutableArray<FLEXGlobalsEntry *> *userGlobalEntries;
 @property (nonatomic, readonly, strong) NSMutableDictionary<NSString *, FLEXCustomContentViewerFuture> *customContentTypeViewers;
 
 @end
@@ -263,7 +263,7 @@
     NSAssert([NSThread isMainThread], @"This method must be called from the main thread.");
 
     entryName = entryName.copy;
-    FLEXGlobalsTableViewControllerEntry *entry = [FLEXGlobalsTableViewControllerEntry entryWithNameFuture:^NSString *{
+    FLEXGlobalsEntry *entry = [FLEXGlobalsEntry entryWithNameFuture:^NSString *{
         return entryName;
     } viewControllerFuture:^UIViewController *{
         return [FLEXObjectExplorerFactory explorerViewControllerForObject:objectFutureBlock()];
@@ -279,7 +279,7 @@
     NSAssert([NSThread isMainThread], @"This method must be called from the main thread.");
 
     entryName = entryName.copy;
-    FLEXGlobalsTableViewControllerEntry *entry = [FLEXGlobalsTableViewControllerEntry entryWithNameFuture:^NSString *{
+    FLEXGlobalsEntry *entry = [FLEXGlobalsEntry entryWithNameFuture:^NSString *{
         return entryName;
     } viewControllerFuture:^UIViewController *{
         UIViewController *viewController = viewControllerFutureBlock();

+ 2 - 2
Classes/Network/FLEXNetworkHistoryTableViewController.h

@@ -7,8 +7,8 @@
 //
 
 #import "FLEXTableViewController.h"
-#import "FLEXGlobalsTableViewControllerEntry.h"
+#import "FLEXGlobalsEntry.h"
 
-@interface FLEXNetworkHistoryTableViewController : FLEXTableViewController <FLEXGlobalsTableViewControllerEntry>
+@interface FLEXNetworkHistoryTableViewController : FLEXTableViewController <FLEXGlobalsEntry>
 
 @end

+ 1 - 1
Classes/Network/FLEXNetworkHistoryTableViewController.m

@@ -154,7 +154,7 @@
     return headerText;
 }
 
-#pragma mark - FLEXGlobalsTableViewControllerEntry
+#pragma mark - FLEXGlobalsEntry
 
 + (NSString *)globalsEntryTitle {
     return @"📡  Network History";

+ 26 - 10
FLEX.xcodeproj/project.pbxproj

@@ -26,8 +26,8 @@
 		3A4C94CA1B5B21410088C3F2 /* FLEXDefaultsExplorerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94411B5B21410088C3F2 /* FLEXDefaultsExplorerViewController.m */; };
 		3A4C94CB1B5B21410088C3F2 /* FLEXDictionaryExplorerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94421B5B21410088C3F2 /* FLEXDictionaryExplorerViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		3A4C94CC1B5B21410088C3F2 /* FLEXDictionaryExplorerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94431B5B21410088C3F2 /* FLEXDictionaryExplorerViewController.m */; };
-		3A4C94CD1B5B21410088C3F2 /* FLEXGlobalsTableViewControllerEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94441B5B21410088C3F2 /* FLEXGlobalsTableViewControllerEntry.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		3A4C94CE1B5B21410088C3F2 /* FLEXGlobalsTableViewControllerEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94451B5B21410088C3F2 /* FLEXGlobalsTableViewControllerEntry.m */; };
+		3A4C94CD1B5B21410088C3F2 /* FLEXGlobalsEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94441B5B21410088C3F2 /* FLEXGlobalsEntry.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		3A4C94CE1B5B21410088C3F2 /* FLEXGlobalsEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94451B5B21410088C3F2 /* FLEXGlobalsEntry.m */; };
 		3A4C94CF1B5B21410088C3F2 /* FLEXImageExplorerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94461B5B21410088C3F2 /* FLEXImageExplorerViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		3A4C94D01B5B21410088C3F2 /* FLEXImageExplorerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94471B5B21410088C3F2 /* FLEXImageExplorerViewController.m */; };
 		3A4C94D11B5B21410088C3F2 /* FLEXLayerExplorerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94481B5B21410088C3F2 /* FLEXLayerExplorerViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -172,6 +172,8 @@
 		C34A70A022B2EC8D009C2C5F /* FLEXBundleExplorerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C34A709E22B2EC8D009C2C5F /* FLEXBundleExplorerViewController.h */; };
 		C34A70A122B2EC8D009C2C5F /* FLEXBundleExplorerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C34A709F22B2EC8D009C2C5F /* FLEXBundleExplorerViewController.m */; };
 		C34EE30821CB23CC00BD3A7C /* FLEXOSLogController.h in Headers */ = {isa = PBXBuildFile; fileRef = C34EE30621CB23CC00BD3A7C /* FLEXOSLogController.h */; };
+		C3511B9122D7C99E0057BAB7 /* FLEXTableViewSection.h in Headers */ = {isa = PBXBuildFile; fileRef = C3511B8F22D7C99E0057BAB7 /* FLEXTableViewSection.h */; };
+		C3511B9222D7C99E0057BAB7 /* FLEXTableViewSection.m in Sources */ = {isa = PBXBuildFile; fileRef = C3511B9022D7C99E0057BAB7 /* FLEXTableViewSection.m */; };
 		C37A0C93218BAC9600848CA7 /* FLEXObjcInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = C37A0C91218BAC9600848CA7 /* FLEXObjcInternal.h */; };
 		C37A0C94218BAC9600848CA7 /* FLEXObjcInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = C37A0C92218BAC9600848CA7 /* FLEXObjcInternal.mm */; };
 		C38DF0EA22CFE4370077B4AD /* FLEXTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38DF0E822CFE4370077B4AD /* FLEXTableViewController.h */; };
@@ -228,8 +230,8 @@
 		3A4C94411B5B21410088C3F2 /* FLEXDefaultsExplorerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXDefaultsExplorerViewController.m; sourceTree = "<group>"; };
 		3A4C94421B5B21410088C3F2 /* FLEXDictionaryExplorerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXDictionaryExplorerViewController.h; sourceTree = "<group>"; };
 		3A4C94431B5B21410088C3F2 /* FLEXDictionaryExplorerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXDictionaryExplorerViewController.m; sourceTree = "<group>"; };
-		3A4C94441B5B21410088C3F2 /* FLEXGlobalsTableViewControllerEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXGlobalsTableViewControllerEntry.h; sourceTree = "<group>"; };
-		3A4C94451B5B21410088C3F2 /* FLEXGlobalsTableViewControllerEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXGlobalsTableViewControllerEntry.m; sourceTree = "<group>"; };
+		3A4C94441B5B21410088C3F2 /* FLEXGlobalsEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXGlobalsEntry.h; sourceTree = "<group>"; };
+		3A4C94451B5B21410088C3F2 /* FLEXGlobalsEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXGlobalsEntry.m; sourceTree = "<group>"; };
 		3A4C94461B5B21410088C3F2 /* FLEXImageExplorerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXImageExplorerViewController.h; sourceTree = "<group>"; };
 		3A4C94471B5B21410088C3F2 /* FLEXImageExplorerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXImageExplorerViewController.m; sourceTree = "<group>"; };
 		3A4C94481B5B21410088C3F2 /* FLEXLayerExplorerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXLayerExplorerViewController.h; sourceTree = "<group>"; };
@@ -377,6 +379,8 @@
 		C34EE30621CB23CC00BD3A7C /* FLEXOSLogController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXOSLogController.h; sourceTree = "<group>"; };
 		C34EE30721CB23CC00BD3A7C /* FLEXOSLogController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXOSLogController.m; sourceTree = "<group>"; };
 		C34EE30A21CB249E00BD3A7C /* ActivityStreamAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ActivityStreamAPI.h; sourceTree = "<group>"; };
+		C3511B8F22D7C99E0057BAB7 /* FLEXTableViewSection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXTableViewSection.h; sourceTree = "<group>"; };
+		C3511B9022D7C99E0057BAB7 /* FLEXTableViewSection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXTableViewSection.m; sourceTree = "<group>"; };
 		C37A0C91218BAC9600848CA7 /* FLEXObjcInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXObjcInternal.h; sourceTree = "<group>"; };
 		C37A0C92218BAC9600848CA7 /* FLEXObjcInternal.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FLEXObjcInternal.mm; sourceTree = "<group>"; };
 		C38DF0E822CFE4370077B4AD /* FLEXTableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXTableViewController.h; sourceTree = "<group>"; };
@@ -593,13 +597,12 @@
 		3A4C949A1B5B21410088C3F2 /* GlobalStateExplorers */ = {
 			isa = PBXGroup;
 			children = (
+				C3511B8E22D7C9740057BAB7 /* Globals */,
 				779B1EBF1C0C4D7C001F5E49 /* DatabaseBrowser */,
 				3A4C94AD1B5B21410088C3F2 /* SystemLog */,
 				C33CF16B22D664E600F9C6C0 /* FileBrowser */,
 				3A4C949B1B5B21410088C3F2 /* FLEXClassesTableViewController.h */,
 				3A4C949C1B5B21410088C3F2 /* FLEXClassesTableViewController.m */,
-				3A4C94A31B5B21410088C3F2 /* FLEXGlobalsTableViewController.h */,
-				3A4C94A41B5B21410088C3F2 /* FLEXGlobalsTableViewController.m */,
 				3A4C94A51B5B21410088C3F2 /* FLEXInstancesTableViewController.h */,
 				3A4C94A61B5B21410088C3F2 /* FLEXInstancesTableViewController.m */,
 				C3DB9F622107FC9600B46809 /* FLEXObjectRef.h */,
@@ -737,11 +740,24 @@
 			path = FileBrowser;
 			sourceTree = "<group>";
 		};
+		C3511B8E22D7C9740057BAB7 /* Globals */ = {
+			isa = PBXGroup;
+			children = (
+				3A4C94A31B5B21410088C3F2 /* FLEXGlobalsTableViewController.h */,
+				3A4C94A41B5B21410088C3F2 /* FLEXGlobalsTableViewController.m */,
+				3A4C94441B5B21410088C3F2 /* FLEXGlobalsEntry.h */,
+				3A4C94451B5B21410088C3F2 /* FLEXGlobalsEntry.m */,
+			);
+			path = Globals;
+			sourceTree = "<group>";
+		};
 		C38DF0E722CFE4140077B4AD /* Core */ = {
 			isa = PBXGroup;
 			children = (
 				C38DF0E822CFE4370077B4AD /* FLEXTableViewController.h */,
 				C38DF0E922CFE4370077B4AD /* FLEXTableViewController.m */,
+				C3511B8F22D7C99E0057BAB7 /* FLEXTableViewSection.h */,
+				C3511B9022D7C99E0057BAB7 /* FLEXTableViewSection.m */,
 			);
 			path = Core;
 			sourceTree = "<group>";
@@ -774,8 +790,6 @@
 				3A4C94411B5B21410088C3F2 /* FLEXDefaultsExplorerViewController.m */,
 				3A4C94421B5B21410088C3F2 /* FLEXDictionaryExplorerViewController.h */,
 				3A4C94431B5B21410088C3F2 /* FLEXDictionaryExplorerViewController.m */,
-				3A4C94441B5B21410088C3F2 /* FLEXGlobalsTableViewControllerEntry.h */,
-				3A4C94451B5B21410088C3F2 /* FLEXGlobalsTableViewControllerEntry.m */,
 				3A4C94461B5B21410088C3F2 /* FLEXImageExplorerViewController.h */,
 				3A4C94471B5B21410088C3F2 /* FLEXImageExplorerViewController.m */,
 				3A4C94481B5B21410088C3F2 /* FLEXLayerExplorerViewController.h */,
@@ -822,6 +836,7 @@
 				3A4C94DB1B5B21410088C3F2 /* FLEXViewExplorerViewController.h in Headers */,
 				3A4C95321B5B21410088C3F2 /* FLEXSystemLogTableViewCell.h in Headers */,
 				3A4C94F91B5B21410088C3F2 /* FLEXArgumentInputNumberView.h in Headers */,
+				C3511B9122D7C99E0057BAB7 /* FLEXTableViewSection.h in Headers */,
 				3A4C953A1B5B21410088C3F2 /* FLEXNetworkSettingsTableViewController.h in Headers */,
 				3A4C94D11B5B21410088C3F2 /* FLEXLayerExplorerViewController.h in Headers */,
 				779B1ED01C0C4D7C001F5E49 /* FLEXMultiColumnTableView.h in Headers */,
@@ -879,7 +894,7 @@
 				3A4C95261B5B21410088C3F2 /* FLEXGlobalsTableViewController.h in Headers */,
 				224D49A81C673AB5000EAB86 /* FLEXRealmDatabaseManager.h in Headers */,
 				7349FD6A22B93CDF00051810 /* FLEXColor.h in Headers */,
-				3A4C94CD1B5B21410088C3F2 /* FLEXGlobalsTableViewControllerEntry.h in Headers */,
+				3A4C94CD1B5B21410088C3F2 /* FLEXGlobalsEntry.h in Headers */,
 				3A4C94FB1B5B21410088C3F2 /* FLEXArgumentInputStringView.h in Headers */,
 				3A4C95421B5B21410088C3F2 /* FLEXNetworkObserver.h in Headers */,
 				C34A70A022B2EC8D009C2C5F /* FLEXBundleExplorerViewController.h in Headers */,
@@ -1031,7 +1046,7 @@
 				3A4C94CA1B5B21410088C3F2 /* FLEXDefaultsExplorerViewController.m in Sources */,
 				3A4C94D01B5B21410088C3F2 /* FLEXImageExplorerViewController.m in Sources */,
 				679F64871BD53B7B00A8C94C /* FLEXCookiesTableViewController.m in Sources */,
-				3A4C94CE1B5B21410088C3F2 /* FLEXGlobalsTableViewControllerEntry.m in Sources */,
+				3A4C94CE1B5B21410088C3F2 /* FLEXGlobalsEntry.m in Sources */,
 				3A4C94FE1B5B21410088C3F2 /* FLEXArgumentInputStructView.m in Sources */,
 				C3F31D402267D883003C991A /* FLEXSubtitleTableViewCell.m in Sources */,
 				3A4C95431B5B21410088C3F2 /* FLEXNetworkObserver.m in Sources */,
@@ -1092,6 +1107,7 @@
 				3A4C952B1B5B21410088C3F2 /* FLEXLibrariesTableViewController.m in Sources */,
 				94A5151E1C4CA1F10063292F /* FLEXExplorerViewController.m in Sources */,
 				3A4C95371B5B21410088C3F2 /* FLEXNetworkHistoryTableViewController.m in Sources */,
+				C3511B9222D7C99E0057BAB7 /* FLEXTableViewSection.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};