Tanner Bennett лет назад: 7
Родитель
Сommit
7979fcd896

+ 2 - 2
Classes/GlobalStateExplorers/FLEXClassesTableViewController.h

@@ -6,9 +6,9 @@
 //  Copyright (c) 2014 Flipboard. All rights reserved.
 //
 
-#import <UIKit/UIKit.h>
+#import "FLEXTableViewController.h"
 
-@interface FLEXClassesTableViewController : UITableViewController
+@interface FLEXClassesTableViewController : FLEXTableViewController
 
 @property (nonatomic, copy) NSString *binaryImageName;
 

+ 4 - 20
Classes/GlobalStateExplorers/FLEXClassesTableViewController.m

@@ -12,11 +12,10 @@
 #import "FLEXUtility.h"
 #import <objc/runtime.h>
 
-@interface FLEXClassesTableViewController () <UISearchBarDelegate>
+@interface FLEXClassesTableViewController ()
 
 @property (nonatomic, strong) NSArray<NSString *> *classNames;
 @property (nonatomic, strong) NSArray<NSString *> *filteredClassNames;
-@property (nonatomic, strong) UISearchBar *searchBar;
 
 @end
 
@@ -26,11 +25,7 @@
 {
     [super viewDidLoad];
     
-    self.searchBar = [[UISearchBar alloc] init];
-    self.searchBar.placeholder = [FLEXUtility searchBarPlaceholderText];
-    self.searchBar.delegate = self;
-    [self.searchBar sizeToFit];
-    self.tableView.tableHeaderView = self.searchBar;
+    self.showsSearchBar = YES;
 }
 
 - (void)setBinaryImageName:(NSString *)binaryImageName
@@ -73,9 +68,9 @@
 }
 
 
-#pragma mark - Search
+#pragma mark - Search bar
 
-- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
+- (void)updateSearchResults:(NSString *)searchText
 {
     if ([searchText length] > 0) {
         NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] %@", searchText];
@@ -87,17 +82,6 @@
     [self.tableView reloadData];
 }
 
-- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
-{
-    [searchBar resignFirstResponder];
-}
-
-- (void)scrollViewDidScroll:(UIScrollView *)scrollView
-{
-    // Dismiss the keyboard when interacting with filtered results.
-    [self.searchBar endEditing:YES];
-}
-
 
 #pragma mark - Table View Data Source
 

+ 2 - 3
Classes/GlobalStateExplorers/FLEXFileBrowserTableViewController.h

@@ -6,11 +6,10 @@
 //  Based on previous work by Evan Doll
 //
 
-#import <UIKit/UIKit.h>
-
+#import "FLEXTableViewController.h"
 #import "FLEXFileBrowserSearchOperation.h"
 
-@interface FLEXFileBrowserTableViewController : UITableViewController
+@interface FLEXFileBrowserTableViewController : FLEXTableViewController
 
 - (id)initWithPath:(NSString *)path;
 

+ 12 - 16
Classes/GlobalStateExplorers/FLEXFileBrowserTableViewController.m

@@ -18,14 +18,13 @@
 @interface FLEXFileBrowserTableViewCell : UITableViewCell
 @end
 
-@interface FLEXFileBrowserTableViewController () <FLEXFileBrowserFileOperationControllerDelegate, FLEXFileBrowserSearchOperationDelegate, UISearchResultsUpdating, UISearchControllerDelegate>
+@interface FLEXFileBrowserTableViewController () <FLEXFileBrowserFileOperationControllerDelegate, FLEXFileBrowserSearchOperationDelegate>
 
 @property (nonatomic, copy) NSString *path;
 @property (nonatomic, copy) NSArray<NSString *> *childPaths;
 @property (nonatomic, strong) NSArray<NSString *> *searchPaths;
 @property (nonatomic, strong) NSNumber *recursiveSize;
 @property (nonatomic, strong) NSNumber *searchPathsSize;
-@property (nonatomic, strong) UISearchController *searchController;
 @property (nonatomic) NSOperationQueue *operationQueue;
 @property (nonatomic, strong) UIDocumentInteractionController *documentController;
 @property (nonatomic, strong) id<FLEXFileBrowserFileOperationController> fileOperationController;
@@ -34,25 +33,20 @@
 
 @implementation FLEXFileBrowserTableViewController
 
-- (id)initWithStyle:(UITableViewStyle)style
+- (id)init
 {
     return [self initWithPath:NSHomeDirectory()];
 }
 
 - (id)initWithPath:(NSString *)path
 {
-    self = [super initWithStyle:UITableViewStyleGrouped];
+    self = [super init];
     if (self) {
         self.path = path;
         self.title = [path lastPathComponent];
         self.operationQueue = [NSOperationQueue new];
-
-        self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
-        self.searchController.searchResultsUpdater = self;
-        self.searchController.delegate = self;
-        self.searchController.dimsBackgroundDuringPresentation = NO;
-        self.tableView.tableHeaderView = self.searchController.searchBar;
-
+        
+        
         //computing path size
         FLEXFileBrowserTableViewController *__weak weakSelf = self;
         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@@ -87,7 +81,9 @@
 - (void)viewDidLoad
 {
     [super viewDidLoad];
-
+    
+    self.showsSearchBar = YES;
+    self.searchBarDebounceInterval = kFLEXDebounceForAsyncSearch;
 }
 
 #pragma mark - Misc
@@ -105,14 +101,14 @@
     [self.tableView reloadData];
 }
 
-#pragma mark - UISearchResultsUpdating
+#pragma mark - Search bar
 
-- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
+- (void)updateSearchResults:(NSString *)newText
 {
     [self reloadDisplayedPaths];
 }
 
-#pragma mark - UISearchControllerDelegate
+#pragma mark UISearchControllerDelegate
 
 - (void)willDismissSearchController:(UISearchController *)searchController
 {
@@ -377,7 +373,7 @@
 
     //clear pre search request and start a new one
     [self.operationQueue cancelAllOperations];
-    FLEXFileBrowserSearchOperation *newOperation = [[FLEXFileBrowserSearchOperation alloc] initWithPath:self.path searchString:self.searchController.searchBar.text];
+    FLEXFileBrowserSearchOperation *newOperation = [[FLEXFileBrowserSearchOperation alloc] initWithPath:self.path searchString:self.searchText];
     newOperation.delegate = self;
     [self.operationQueue addOperation:newOperation];
 }

+ 2 - 2
Classes/GlobalStateExplorers/FLEXLibrariesTableViewController.h

@@ -6,8 +6,8 @@
 //  Copyright (c) 2014 Flipboard. All rights reserved.
 //
 
-#import <UIKit/UIKit.h>
+#import "FLEXTableViewController.h"
 
-@interface FLEXLibrariesTableViewController : UITableViewController
+@interface FLEXLibrariesTableViewController : FLEXTableViewController
 
 @end

+ 5 - 15
Classes/GlobalStateExplorers/FLEXLibrariesTableViewController.m

@@ -12,12 +12,11 @@
 #import "FLEXClassExplorerViewController.h"
 #import <objc/runtime.h>
 
-@interface FLEXLibrariesTableViewController () <UISearchBarDelegate>
+@interface FLEXLibrariesTableViewController ()
 
 @property (nonatomic, strong) NSArray<NSString *> *imageNames;
 @property (nonatomic, strong) NSArray<NSString *> *filteredImageNames;
 
-@property (nonatomic, strong) UISearchBar *searchBar;
 @property (nonatomic, strong) Class foundClass;
 
 @end
@@ -37,11 +36,7 @@
 {
     [super viewDidLoad];
     
-    self.searchBar = [[UISearchBar alloc] init];
-    self.searchBar.delegate = self;
-    self.searchBar.placeholder = [FLEXUtility searchBarPlaceholderText];
-    [self.searchBar sizeToFit];
-    self.tableView.tableHeaderView = self.searchBar;
+    self.showsSearchBar = YES;
 }
 
 
@@ -94,9 +89,9 @@
 
 #pragma mark - Filtering
 
-- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
+- (void)updateSearchResults:(NSString *)searchText
 {
-    if ([searchText length] > 0) {
+    if (searchText.length) {
         NSPredicate *searchPredicate = [NSPredicate predicateWithBlock:^BOOL(NSString *evaluatedObject, NSDictionary<NSString *, id> *bindings) {
             BOOL matches = NO;
             NSString *shortName = [self shortNameForImageName:evaluatedObject];
@@ -114,11 +109,6 @@
     [self.tableView reloadData];
 }
 
-- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
-{
-    [searchBar resignFirstResponder];
-}
-
 
 #pragma mark - Table View Data Source
 
@@ -145,7 +135,7 @@
     NSString *executablePath;
     if (self.foundClass) {
         if (indexPath.row == 0) {
-            cell.textLabel.text = [NSString stringWithFormat:@"Class \"%@\"", self.searchBar.text];
+            cell.textLabel.text = [NSString stringWithFormat:@"Class \"%@\"", self.searchText];
             return cell;
         } else {
             executablePath = self.filteredImageNames[indexPath.row-1];

+ 2 - 2
Classes/GlobalStateExplorers/FLEXLiveObjectsTableViewController.h

@@ -6,8 +6,8 @@
 //  Copyright (c) 2014 Flipboard. All rights reserved.
 //
 
-#import <UIKit/UIKit.h>
+#import "FLEXTableViewController.h"
 
-@interface FLEXLiveObjectsTableViewController : UITableViewController
+@interface FLEXLiveObjectsTableViewController : FLEXTableViewController
 
 @end

+ 17 - 35
Classes/GlobalStateExplorers/FLEXLiveObjectsTableViewController.m

@@ -16,13 +16,12 @@ static const NSInteger kFLEXLiveObjectsSortAlphabeticallyIndex = 0;
 static const NSInteger kFLEXLiveObjectsSortByCountIndex = 1;
 static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
 
-@interface FLEXLiveObjectsTableViewController () <UISearchBarDelegate>
+@interface FLEXLiveObjectsTableViewController ()
 
 @property (nonatomic, strong) NSDictionary<NSString *, NSNumber *> *instanceCountsForClassNames;
 @property (nonatomic, strong) NSDictionary<NSString *, NSNumber *> *instanceSizesForClassNames;
 @property (nonatomic, readonly) NSArray<NSString *> *allClassNames;
 @property (nonatomic, strong) NSArray<NSString *> *filteredClassNames;
-@property (nonatomic, strong) UISearchBar *searchBar;
 
 @end
 
@@ -32,13 +31,10 @@ static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
 {
     [super viewDidLoad];
     
-    self.searchBar = [[UISearchBar alloc] init];
-    self.searchBar.placeholder = [FLEXUtility searchBarPlaceholderText];
-    self.searchBar.delegate = self;
-    self.searchBar.showsScopeBar = YES;
-    self.searchBar.scopeButtonTitles = @[@"Sort Alphabetically", @"Sort by Count", @"Sort by Size"];
-    [self.searchBar sizeToFit];
-    self.tableView.tableHeaderView = self.searchBar;
+    self.showsSearchBar = YES;
+    self.searchBarDebounceInterval = kFLEXDebounceInstant;
+    self.searchController.searchBar.showsScopeBar = YES;
+    self.searchController.searchBar.scopeButtonTitles = @[@"Sort Alphabetically", @"Sort by Count", @"Sort by Size"];
     
     self.refreshControl = [[UIRefreshControl alloc] init];
     [self.refreshControl addTarget:self action:@selector(refreshControlDidRefresh:) forControlEvents:UIControlEventValueChanged];
@@ -90,7 +86,7 @@ static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
     self.instanceCountsForClassNames = mutableCountsForClassNames;
     self.instanceSizesForClassNames = mutableSizesForClassNames;
     
-    [self updateTableDataForSearchFilter];
+    [self updateTableDataForSearchFilter:nil];
 }
 
 - (void)refreshControlDidRefresh:(id)sender
@@ -131,48 +127,34 @@ static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
 }
 
 
-#pragma mark - Search
+#pragma mark - Search bar
 
-- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
+- (void)updateSearchResults:(NSString *)newText
 {
-    [self updateTableDataForSearchFilter];
+    [self updateTableDataForSearchFilter:newText];
 }
 
-- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
+- (void)updateTableDataForSearchFilter:(NSString *)filter
 {
-    [searchBar resignFirstResponder];
-}
-
-- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope
-{
-    [self updateTableDataForSearchFilter];
-}
-
-- (void)scrollViewDidScroll:(UIScrollView *)scrollView
-{
-    // Dismiss the keyboard when interacting with filtered results.
-    [self.searchBar endEditing:YES];
-}
-
-- (void)updateTableDataForSearchFilter
-{
-    if ([self.searchBar.text length] > 0) {
-        NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] %@", self.searchBar.text];
+    NSInteger selectedScope = self.searchController.searchBar.selectedScopeButtonIndex;
+    
+    if (filter.length) {
+        NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] %@", filter];
         self.filteredClassNames = [self.allClassNames filteredArrayUsingPredicate:searchPredicate];
     } else {
         self.filteredClassNames = self.allClassNames;
     }
     
-    if (self.searchBar.selectedScopeButtonIndex == kFLEXLiveObjectsSortAlphabeticallyIndex) {
+    if (selectedScope == kFLEXLiveObjectsSortAlphabeticallyIndex) {
         self.filteredClassNames = [self.filteredClassNames sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
-    } else if (self.searchBar.selectedScopeButtonIndex == kFLEXLiveObjectsSortByCountIndex) {
+    } else if (selectedScope == kFLEXLiveObjectsSortByCountIndex) {
         self.filteredClassNames = [self.filteredClassNames sortedArrayUsingComparator:^NSComparisonResult(NSString *className1, NSString *className2) {
             NSNumber *count1 = self.instanceCountsForClassNames[className1];
             NSNumber *count2 = self.instanceCountsForClassNames[className2];
             // Reversed for descending counts.
             return [count2 compare:count1];
         }];
-    } else if (self.searchBar.selectedScopeButtonIndex == kFLEXLiveObjectsSortBySizeIndex) {
+    } else if (selectedScope == kFLEXLiveObjectsSortBySizeIndex) {
         self.filteredClassNames = [self.filteredClassNames sortedArrayUsingComparator:^NSComparisonResult(NSString *className1, NSString *className2) {
             NSNumber *count1 = self.instanceCountsForClassNames[className1];
             NSNumber *count2 = self.instanceCountsForClassNames[className2];

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

@@ -6,8 +6,8 @@
 //  Copyright (c) 2015 f. All rights reserved.
 //
 
-#import <UIKit/UIKit.h>
+#import "FLEXTableViewController.h"
 
-@interface FLEXSystemLogTableViewController : UITableViewController
+@interface FLEXSystemLogTableViewController : FLEXTableViewController
 
 @end

+ 21 - 24
Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogTableViewController.m

@@ -13,9 +13,8 @@
 #import "FLEXOSLogController.h"
 #import "FLEXSystemLogTableViewCell.h"
 
-@interface FLEXSystemLogTableViewController () <UISearchResultsUpdating, UISearchControllerDelegate>
+@interface FLEXSystemLogTableViewController ()
 
-@property (nonatomic, strong) UISearchController *searchController;
 @property (nonatomic, readonly) id<FLEXLogController> logController;
 @property (nonatomic, readonly) NSMutableArray<FLEXSystemLogMessage *> *logMessages;
 @property (nonatomic, copy) NSArray<FLEXSystemLogMessage *> *filteredLogMessages;
@@ -24,9 +23,15 @@
 
 @implementation FLEXSystemLogTableViewController
 
+- (id)init {
+    return [super initWithStyle:UITableViewStylePlain];
+}
+
 - (void)viewDidLoad
 {
     [super viewDidLoad];
+    
+    self.showsSearchBar = YES;
 
     __weak __typeof(self) weakSelf = self;
     id logHandler = ^(NSArray<FLEXSystemLogMessage *> *newMessages) {
@@ -35,10 +40,10 @@
     };
 
     _logMessages = [NSMutableArray array];
-    if ([NSProcessInfo processInfo].operatingSystemVersion.majorVersion <= 9) {
-        _logController = [FLEXASLLogController withUpdateHandler:logHandler];
-    } else {
+    if (FLEXOSLogAvailable()) {
         _logController = [FLEXOSLogController withUpdateHandler:logHandler];
+    } else {
+        _logController = [FLEXASLLogController withUpdateHandler:logHandler];
     }
 
     [self.tableView registerClass:[FLEXSystemLogTableViewCell class] forCellReuseIdentifier:kFLEXSystemLogTableViewCellIdentifier];
@@ -58,12 +63,6 @@
     } else {
         self.navigationItem.rightBarButtonItem = scrollDown;
     }
-    
-    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
-    self.searchController.delegate = self;
-    self.searchController.searchResultsUpdater = self;
-    self.searchController.dimsBackgroundDuringPresentation = NO;
-    self.tableView.tableHeaderView = self.searchController.searchBar;
 }
 
 - (void)handleUpdateWithNewMessages:(NSArray<FLEXSystemLogMessage *> *)newMessages
@@ -133,7 +132,7 @@
 {
     FLEXSystemLogTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kFLEXSystemLogTableViewCellIdentifier forIndexPath:indexPath];
     cell.logMessage = [self logMessageAtIndexPath:indexPath];
-    cell.highlightedText = self.searchController.searchBar.text;
+    cell.highlightedText = self.searchText;
     
     if (indexPath.row % 2 == 0) {
         cell.backgroundColor = [FLEXColor primaryBackgroundColor];
@@ -175,23 +174,21 @@
     return self.searchController.isActive ? self.filteredLogMessages[indexPath.row] : self.logMessages[indexPath.row];
 }
 
-#pragma mark - UISearchResultsUpdating
+#pragma mark - Search bar
 
-- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
+- (void)updateSearchResults:(NSString *)searchString
 {
-    NSString *searchString = searchController.searchBar.text;
-    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-        NSArray<FLEXSystemLogMessage *> *filteredLogMessages = [self.logMessages filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(FLEXSystemLogMessage *logMessage, NSDictionary<NSString *, id> *bindings) {
+    [self onBackgroundQueue:^NSArray *{
+        return [self.logMessages filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(FLEXSystemLogMessage *logMessage, NSDictionary<NSString *, id> *bindings) {
             NSString *displayedText = [FLEXSystemLogTableViewCell displayedTextForLogMessage:logMessage];
             return [displayedText rangeOfString:searchString options:NSCaseInsensitiveSearch].length > 0;
         }]];
-        dispatch_async(dispatch_get_main_queue(), ^{
-            if ([searchController.searchBar.text isEqual:searchString]) {
-                self.filteredLogMessages = filteredLogMessages;
-                [self.tableView reloadData];
-            }
-        });
-    });
+    } thenOnMainQueue:^(NSArray *filteredLogMessages) {
+        if ([self.searchText isEqual:searchString]) {
+            self.filteredLogMessages = filteredLogMessages;
+            [self.tableView reloadData];
+        }
+    }];
 }
 
 @end

+ 2 - 2
Classes/Network/FLEXNetworkHistoryTableViewController.h

@@ -6,8 +6,8 @@
 //  Copyright (c) 2015 Flipboard. All rights reserved.
 //
 
-#import <UIKit/UIKit.h>
+#import "FLEXTableViewController.h"
 
-@interface FLEXNetworkHistoryTableViewController : UITableViewController
+@interface FLEXNetworkHistoryTableViewController : FLEXTableViewController
 
 @end

+ 17 - 30
Classes/Network/FLEXNetworkHistoryTableViewController.m

@@ -15,7 +15,7 @@
 #import "FLEXNetworkObserver.h"
 #import "FLEXNetworkSettingsTableViewController.h"
 
-@interface FLEXNetworkHistoryTableViewController () <UISearchResultsUpdating, UISearchControllerDelegate>
+@interface FLEXNetworkHistoryTableViewController ()
 
 /// Backing model
 @property (nonatomic, copy) NSArray<FLEXNetworkTransaction *> *networkTransactions;
@@ -26,15 +26,13 @@
 @property (nonatomic, assign) BOOL rowInsertInProgress;
 @property (nonatomic, assign) BOOL isPresentingSearch;
 
-@property (nonatomic, strong) UISearchController *searchController;
-
 @end
 
 @implementation FLEXNetworkHistoryTableViewController
 
-- (instancetype)initWithStyle:(UITableViewStyle)style
+- (id)init
 {
-    self = [super initWithStyle:style];
+    self = [super initWithStyle:UITableViewStylePlain];
     if (self) {
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNewTransactionRecordedNotification:) name:kFLEXNetworkRecorderNewTransactionNotification object:nil];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTransactionUpdatedNotification:) name:kFLEXNetworkRecorderTransactionUpdatedNotification object:nil];
@@ -59,16 +57,12 @@
 {
     [super viewDidLoad];
 
+    self.showsSearchBar = YES;
+
     [self.tableView registerClass:[FLEXNetworkTransactionTableViewCell class] forCellReuseIdentifier:kFLEXNetworkTransactionCellIdentifier];
     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
     self.tableView.rowHeight = [FLEXNetworkTransactionTableViewCell preferredCellHeight];
 
-    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
-    self.searchController.delegate = self;
-    self.searchController.searchResultsUpdater = self;
-    self.searchController.dimsBackgroundDuringPresentation = NO;
-    self.tableView.tableHeaderView = self.searchController.searchBar;
-
     [self updateTransactions];
 }
 
@@ -177,7 +171,7 @@
     
     if (self.searchController.isActive) {
         [self updateTransactions];
-        [self updateSearchResults];
+        [self updateSearchResults:nil];
         return;
     }
 
@@ -322,30 +316,23 @@
     return self.searchController.isActive ? self.filteredNetworkTransactions[indexPath.row] : self.networkTransactions[indexPath.row];
 }
 
-#pragma mark - UISearchResultsUpdating
+#pragma mark - Search Bar
 
-- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
+- (void)updateSearchResults:(NSString *)searchString
 {
-    [self updateSearchResults];
-}
-
-- (void)updateSearchResults
-{
-    NSString *searchString = self.searchController.searchBar.text;
-    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-        NSArray<FLEXNetworkTransaction *> *filteredNetworkTransactions = [self.networkTransactions filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(FLEXNetworkTransaction *transaction, NSDictionary<NSString *, id> *bindings) {
+    [self onBackgroundQueue:^NSArray *{
+        return [self.networkTransactions filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(FLEXNetworkTransaction *transaction, NSDictionary<NSString *, id> *bindings) {
             return [[transaction.request.URL absoluteString] rangeOfString:searchString options:NSCaseInsensitiveSearch].length > 0;
         }]];
-        dispatch_async(dispatch_get_main_queue(), ^{
-            if ([self.searchController.searchBar.text isEqual:searchString]) {
-                self.filteredNetworkTransactions = filteredNetworkTransactions;
-                [self.tableView reloadData];
-            }
-        });
-    });
+    } thenOnMainQueue:^(NSArray *filteredNetworkTransactions) {
+        if ([self.searchText isEqual:searchString]) {
+            self.filteredNetworkTransactions = filteredNetworkTransactions;
+            [self.tableView reloadData];
+        }
+    }];
 }
 
-#pragma mark - UISearchControllerDelegate
+#pragma mark UISearchControllerDelegate
 
 - (void)willPresentSearchController:(UISearchController *)searchController
 {

+ 2 - 2
Classes/ObjectExplorers/Controllers/FLEXObjectExplorerViewController.h

@@ -6,7 +6,7 @@
 //  Copyright (c) 2014 Flipboard. All rights reserved.
 //
 
-#import <UIKit/UIKit.h>
+#import "FLEXTableViewController.h"
 
 typedef NS_ENUM(NSUInteger, FLEXObjectExplorerSection) {
     FLEXObjectExplorerSectionDescription,
@@ -19,7 +19,7 @@ typedef NS_ENUM(NSUInteger, FLEXObjectExplorerSection) {
     FLEXObjectExplorerSectionReferencingInstances
 };
 
-@interface FLEXObjectExplorerViewController : UITableViewController
+@interface FLEXObjectExplorerViewController : FLEXTableViewController
 
 @property (nonatomic, strong) id object;
 

+ 16 - 33
Classes/ObjectExplorers/Controllers/FLEXObjectExplorerViewController.m

@@ -51,7 +51,7 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
 @implementation FLEXMethodBox
 @end
 
-@interface FLEXObjectExplorerViewController () <UISearchBarDelegate>
+@interface FLEXObjectExplorerViewController ()
 
 @property (nonatomic, strong) NSArray<FLEXPropertyBox *> *properties;
 @property (nonatomic, strong) NSArray<FLEXPropertyBox *> *propertiesWithParent;
@@ -83,7 +83,6 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
 @property (nonatomic, strong) NSArray *cachedCustomSectionRowCookies;
 @property (nonatomic, strong) NSIndexSet *customSectionVisibleIndexes;
 
-@property (nonatomic, strong) UISearchBar *searchBar;
 @property (nonatomic, strong) NSString *filterText;
 @property (nonatomic, assign) FLEXObjectExplorerScope scope;
 
@@ -110,12 +109,10 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
 {
     [super viewDidLoad];
     
-    self.searchBar = [[UISearchBar alloc] init];
-    self.searchBar.placeholder = [FLEXUtility searchBarPlaceholderText];
-    self.searchBar.delegate = self;
-    self.searchBar.showsScopeBar = YES;
+    self.showsSearchBar = YES;
+    self.searchBarDebounceInterval = kFLEXDebounceInstant;
+    self.searchController.searchBar.showsScopeBar = YES;
     [self refreshScopeTitles];
-    self.tableView.tableHeaderView = self.searchBar;
     
     self.refreshControl = [[UIRefreshControl alloc] init];
     [self.refreshControl addTarget:self action:@selector(refreshControlDidRefresh:) forControlEvents:UIControlEventValueChanged];
@@ -132,7 +129,7 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
 
 - (void)scrollViewDidScroll:(UIScrollView *)scrollView
 {
-    [self.searchBar endEditing:YES];
+    [self.searchController.searchBar endEditing:YES];
 }
 
 - (void)refreshControlDidRefresh:(id)sender
@@ -146,7 +143,7 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
 
 - (void)refreshScopeTitles
 {
-    if (!self.searchBar) return;
+    if (!self.searchController.searchBar) return;
 
     Class parent = [self.object superclass];
     Class parentSuper = [parent superclass];
@@ -162,25 +159,20 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
         [scopes addObject:@"NSObject"];
     }
 
-    self.searchBar.scopeButtonTitles = scopes;
-    [self.searchBar sizeToFit];
+    self.searchController.searchBar.scopeButtonTitles = scopes;
     [self updateTableData];
 }
 
-- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
+- (void)updateSearchResults:(NSString *)newText;
 {
-    self.filterText = searchText;
-}
-
-- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
-{
-    [searchBar resignFirstResponder];
-}
-
-- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope
-{
-    self.scope = selectedScope;
-    [self updateDisplayedData];
+    NSInteger newScope = self.searchController.searchBar.selectedScopeButtonIndex;
+    BOOL delta = self.scope != newScope || ![self.filterText isEqualToString:newText];
+    
+    if (delta) {
+        self.scope = newScope;
+        self.filterText = newText;
+        [self updateDisplayedData];
+    }
 }
 
 - (NSArray *)metadata:(FLEXMetadataKind)metadataKind forScope:(FLEXObjectExplorerScope)scope
@@ -248,15 +240,6 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
     [self refreshScopeTitles];
 }
 
-- (void)setFilterText:(NSString *)filterText
-{
-    if (_filterText != filterText || ![_filterText isEqual:filterText]) {
-        _filterText = filterText;
-        [self updateDisplayedData];
-    }
-}
-
-
 #pragma mark - Reloading
 
 - (void)updateTableData

+ 0 - 1
Classes/Utility/FLEXUtility.h

@@ -45,7 +45,6 @@
 + (UIFont *)defaultTableViewCellLabelFont;
 + (NSString *)stringByEscapingHTMLEntitiesInString:(NSString *)originalString;
 + (UIInterfaceOrientationMask)infoPlistSupportedInterfaceOrientationsMask;
-+ (NSString *)searchBarPlaceholderText;
 + (UIImage *)thumbnailedImageWithMaxPixelDimension:(NSInteger)dimension fromImageData:(NSData *)data;
 + (NSString *)stringFromRequestDuration:(NSTimeInterval)duration;
 + (NSString *)statusCodeStringFromURLResponse:(NSURLResponse *)response;

+ 0 - 5
Classes/Utility/FLEXUtility.m

@@ -223,11 +223,6 @@
     return supportedOrientationsMask;
 }
 
-+ (NSString *)searchBarPlaceholderText
-{
-    return @"Filter";
-}
-
 + (UIImage *)thumbnailedImageWithMaxPixelDimension:(NSInteger)dimension fromImageData:(NSData *)data
 {
     UIImage *thumbnail = nil;

+ 2 - 2
Classes/ViewHierarchy/FLEXHierarchyTableViewController.h

@@ -6,11 +6,11 @@
 //  Copyright (c) 2014 Flipboard. All rights reserved.
 //
 
-#import <UIKit/UIKit.h>
+#import "FLEXTableViewController.h"
 
 @protocol FLEXHierarchyTableViewControllerDelegate;
 
-@interface FLEXHierarchyTableViewController : UITableViewController
+@interface FLEXHierarchyTableViewController : FLEXTableViewController
 
 - (instancetype)initWithViews:(NSArray<UIView *> *)allViews viewsAtTap:(NSArray<UIView *> *)viewsAtTap selectedView:(UIView *)selectedView depths:(NSDictionary<NSValue *, NSNumber *> *)depthsForViews;
 

+ 16 - 30
Classes/ViewHierarchy/FLEXHierarchyTableViewController.m

@@ -17,7 +17,7 @@
 static const NSInteger kFLEXHierarchyScopeViewsAtTapIndex = 0;
 static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
 
-@interface FLEXHierarchyTableViewController () <UISearchBarDelegate>
+@interface FLEXHierarchyTableViewController ()
 
 @property (nonatomic, strong) NSArray<UIView *> *allViews;
 @property (nonatomic, strong) NSDictionary<NSValue *, NSNumber *> *depthsForViews;
@@ -25,8 +25,6 @@ static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
 @property (nonatomic, strong) UIView *selectedView;
 @property (nonatomic, strong) NSArray<UIView *> *displayedViews;
 
-@property (nonatomic, strong) UISearchBar *searchBar;
-
 @end
 
 @implementation FLEXHierarchyTableViewController
@@ -60,15 +58,14 @@ static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
     // Separator inset clashes with persistent cell selection.
     [self.tableView setSeparatorInset:UIEdgeInsetsZero];
     
-    self.searchBar = [[UISearchBar alloc] init];
-    self.searchBar.placeholder = [FLEXUtility searchBarPlaceholderText];
-    self.searchBar.delegate = self;
+    self.showsSearchBar = YES;
+    self.pinSearchBar = YES;
+    self.searchBarDebounceInterval = kFLEXDebounceInstant;
+    self.automaticallyShowsSearchBarCancelButton = NO;
     if ([self showScopeBar]) {
-        self.searchBar.showsScopeBar = YES;
-        self.searchBar.scopeButtonTitles = @[@"Views at Tap", @"Full Hierarchy"];
+        self.searchController.searchBar.showsScopeBar = YES;
+        self.searchController.searchBar.scopeButtonTitles = @[@"Views at Tap", @"Full Hierarchy"];
     }
-    [self.searchBar sizeToFit];
-    self.tableView.tableHeaderView = self.searchBar;
     
     [self updateDisplayedViews];
 }
@@ -96,21 +93,21 @@ static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
 {
     NSArray<UIView *> *candidateViews = nil;
     if ([self showScopeBar]) {
-        if (self.searchBar.selectedScopeButtonIndex == kFLEXHierarchyScopeViewsAtTapIndex) {
+        if (self.selectedScope == kFLEXHierarchyScopeViewsAtTapIndex) {
             candidateViews = self.viewsAtTap;
-        } else if (self.searchBar.selectedScopeButtonIndex == kFLEXHierarchyScopeFullHierarchyIndex) {
+        } else if (self.selectedScope == kFLEXHierarchyScopeFullHierarchyIndex) {
             candidateViews = self.allViews;
         }
     } else {
         candidateViews = self.allViews;
     }
     
-    if ([self.searchBar.text length] > 0) {
+    if (self.searchText.length) {
         self.displayedViews = [candidateViews filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *candidateView, NSDictionary<NSString *, id> *bindings) {
             NSString *title = [FLEXUtility descriptionForView:candidateView includingFrame:NO];
             NSString *candidateViewPointerAddress = [NSString stringWithFormat:@"%p", candidateView];
-            BOOL matchedViewPointerAddress = [candidateViewPointerAddress rangeOfString:self.searchBar.text options:NSCaseInsensitiveSearch].location != NSNotFound;
-            BOOL matchedViewTitle = [title rangeOfString:self.searchBar.text options:NSCaseInsensitiveSearch].location != NSNotFound;
+            BOOL matchedViewPointerAddress = [candidateViewPointerAddress rangeOfString:self.searchText options:NSCaseInsensitiveSearch].location != NSNotFound;
+            BOOL matchedViewTitle = [title rangeOfString:self.searchText options:NSCaseInsensitiveSearch].location != NSNotFound;
             return matchedViewPointerAddress || matchedViewTitle;
         }]];
     } else {
@@ -120,33 +117,23 @@ static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
     [self.tableView reloadData];
 }
 
+#pragma mark - Search Bar
+
 - (BOOL)showScopeBar
 {
     return [self.viewsAtTap count] > 0;
 }
 
-- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope
+- (void)updateSearchResults:(NSString *)newText
 {
     [self updateDisplayedViews];
     
     // If the search bar text field is active, don't scroll on selection because we may want to continue typing.
     // Otherwise, scroll so that the selected cell is visible.
-    UITableViewScrollPosition scrollPosition = self.searchBar.isFirstResponder ? UITableViewScrollPositionNone : UITableViewScrollPositionMiddle;
+    UITableViewScrollPosition scrollPosition = self.searchController.searchBar.isFirstResponder ? UITableViewScrollPositionNone : UITableViewScrollPositionMiddle;
     [self trySelectCellForSelectedViewWithScrollPosition:scrollPosition];
 }
 
-- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
-{
-    [self updateDisplayedViews];
-    [self trySelectCellForSelectedViewWithScrollPosition:UITableViewScrollPositionNone];
-}
-
-- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
-{
-    [searchBar resignFirstResponder];
-}
-
-
 #pragma mark - Table View Data Source
 
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
@@ -212,7 +199,6 @@ static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
     [self.navigationController pushViewController:viewExplorer animated:YES];
 }
 
-
 #pragma mark - Button Actions
 
 - (void)donePressed:(id)sender