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

Runtime browser improvements

Tanner Bennett пре 6 година
родитељ
комит
82f104d682

+ 29 - 14
Classes/GlobalStateExplorers/RuntimeBrowser/TBKeyPathSearchController.m

@@ -19,7 +19,7 @@
 
 @interface TBKeyPathSearchController ()
 @property (nonatomic, readonly, weak) id<TBKeyPathSearchControllerDelegate> delegate;
-@property (nonatomic, readonly) NSTimer *timer;
+@property (nonatomic) NSTimer *timer;
 @property (nonatomic) NSArray<NSString*> *bundlesOrClasses;
 @property (nonatomic) TBKeyPath *keyPath;
 
@@ -29,6 +29,9 @@
 /// or (2) when the class key is a wildcard and we're searching methods in many
 /// classes at once. Each list in \c classesToMethods correspnds to a class here.
 @property (nonatomic) NSArray<NSString *> *classes;
+/// A filtered version of \c classes used when searching for a specific attribute.
+/// Classes with no matching ivars/properties/methods are not shown.
+@property (nonatomic) NSArray<NSString *> *filteredClasses;
 // We use this regardless of whether the target class is absolute, just as above
 @property (nonatomic) NSArray<NSArray<FLEXMethod *> *> *classesToMethods;
 @end
@@ -95,6 +98,7 @@
         [self didSelectAbsoluteClass:text];
     } else {
         self.classes = nil;
+        self.filteredClasses = nil;
     }
 
     [self updateTable];
@@ -102,6 +106,7 @@
 
 - (void)didSelectAbsoluteClass:(NSString *)name {
     self.classes          = [self classesOf:name];
+    self.filteredClasses  = self.classes;
     self.bundlesOrClasses = nil;
     self.classesToMethods = nil;
 }
@@ -124,11 +129,19 @@
             // Here, our class key is 'absolute'; .classes is a list of superclasses
             // and we want to show the methods for those classes specifically
             // TODO: add caching to this somehow
-            self.classesToMethods = [TBRuntimeController
+            NSMutableArray *methods = [TBRuntimeController
                 methodsForToken:self.keyPath.methodKey
                 instance:self.keyPath.instanceMethods
                 inClasses:self.classes
-            ];
+            ].mutableCopy;
+            
+            // Remove classes without results if we're searching for a method
+            TBToken *methodKey = self.keyPath.methodKey;
+            if (methodKey && !methodKey.isAny) {
+                [self setNonEmptyMethodLists:methods withClasses:self.classes.mutableCopy];
+            } else {
+                self.filteredClasses = self.classes;
+            }
         }
         else {
             TBKeyPath *keyPath = self.keyPath;
@@ -138,6 +151,7 @@
                 
                 NSMutableArray *methods = models.mutableCopy;
                 NSMutableArray *classes = [TBRuntimeController classesForKeyPath:keyPath];
+                self.classes = classes.copy;
                 [self setNonEmptyMethodLists:methods withClasses:classes];
             } else { // We're looking at bundles or classes
                 self.bundlesOrClasses = models;
@@ -152,7 +166,7 @@
     });
 }
 
-/// Assign .classes and .classesToMethods after removing empty sections
+/// Assign assign .filteredClasses and .classesToMethods after removing empty sections
 - (void)setNonEmptyMethodLists:(NSMutableArray<NSArray *> *)methods withClasses:(NSMutableArray *)classes {
     // Remove sections with no methods
     NSIndexSet *allEmpty = [methods indexesOfObjectsPassingTest:^BOOL(NSArray *list, NSUInteger idx, BOOL *stop) {
@@ -161,7 +175,7 @@
     [methods removeObjectsAtIndexes:allEmpty];
     [classes removeObjectsAtIndexes:allEmpty];
     
-    self.classes = classes;
+    self.filteredClasses = classes;
     self.classesToMethods = methods;
 }
 
@@ -201,9 +215,10 @@
     if (searchText.length) {
         if (!self.keyPath.methodKey) {
             self.classes = nil;
+            self.filteredClasses = nil;
         }
 
-        _timer = [NSTimer fireSecondsFromNow:0.15 block:^{
+        self.timer = [NSTimer fireSecondsFromNow:0.15 block:^{
             [self updateTable];
         }];
     }
@@ -236,11 +251,11 @@
 #pragma mark UITableViewDataSource
 
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
-    return self.classes.count ?: 1;
+    return self.filteredClasses.count ?: 1;
 }
 
 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
-    return self.classes.count ? 1 : self.bundlesOrClasses.count;
+    return self.filteredClasses.count ? 1 : self.bundlesOrClasses.count;
 }
 
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
@@ -258,7 +273,7 @@
         }
     }
     // One row per section
-    else if (self.classes.count) {
+    else if (self.filteredClasses.count) {
         NSArray<FLEXMethod *> *methods = self.classesToMethods[indexPath.section];
         NSMutableString *summary = [NSMutableString new];
         [methods enumerateObjectsUsingBlock:^(FLEXMethod *method, NSUInteger idx, BOOL *stop) {
@@ -277,7 +292,7 @@
         }];
 
         cell.accessoryType        = UITableViewCellAccessoryDisclosureIndicator;
-        cell.textLabel.text       = self.classes[indexPath.section];
+        cell.textLabel.text       = self.filteredClasses[indexPath.section];
         cell.detailTextLabel.text = summary.length ? summary : nil;
 
     }
@@ -289,7 +304,7 @@
 }
 
 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
-    if (self.classes || self.keyPath.methodKey) {
+    if (self.filteredClasses || self.keyPath.methodKey) {
         return @" ";
     } else if (self.bundlesOrClasses) {
         NSInteger count = self.bundlesOrClasses.count;
@@ -304,7 +319,7 @@
 }
 
 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
-    if (self.classes || self.keyPath.methodKey) {
+    if (self.filteredClasses || self.keyPath.methodKey) {
         if (section == 0) {
             return 55;
         }
@@ -328,8 +343,8 @@
             [self didSelectKeyPathOption:bundleSuffixOrClass];
         }
     } else {
-        if (self.classes) {
-            Class cls = NSClassFromString(self.classes[indexPath.section]);
+        if (self.filteredClasses.count) {
+            Class cls = NSClassFromString(self.filteredClasses[indexPath.section]);
             NSParameterAssert(cls);
             [self.delegate didSelectClass:cls];
         } else {

+ 4 - 0
Classes/Utility/Runtime/FLEXTypeEncodingParser.m

@@ -109,6 +109,10 @@ BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *al
 #pragma mark Public
 
 + (BOOL)methodTypeEncodingSupported:(NSString *)typeEncoding cleaned:(NSString * __autoreleasing *)cleanedEncoding {
+    if (!typeEncoding.length) {
+        return NO;
+    }
+    
     FLEXTypeEncodingParser *parser = [[self alloc] initWithObjCTypes:typeEncoding];
     
     while (!parser.scan.isAtEnd) {