Explorar el Código

Add a section to the object explorer for finding all other objects with ivars referencing the current object.

Ryan Olson hace 12 años
padre
commit
1bd6c7164e

+ 1 - 2
Classes/Global State Explorers/FLEXInstancesTableViewController.h

@@ -10,8 +10,7 @@
 
 @interface FLEXInstancesTableViewController : UITableViewController
 
-@property (nonatomic, strong) NSArray *instances;
-
 + (instancetype)instancesTableViewControllerForClassName:(NSString *)className;
++ (instancetype)instancesTableViewControllerForInstancesReferencingObject:(id)object;
 
 @end

+ 44 - 1
Classes/Global State Explorers/FLEXInstancesTableViewController.m

@@ -15,6 +15,9 @@
 
 @interface FLEXInstancesTableViewController ()
 
+@property (nonatomic, strong) NSArray *instances;
+@property (nonatomic, strong) NSArray *fieldNames;
+
 @end
 
 @implementation FLEXInstancesTableViewController
@@ -37,6 +40,40 @@
     return instancesViewController;
 }
 
++ (instancetype)instancesTableViewControllerForInstancesReferencingObject:(id)object
+{
+    NSMutableArray *instances = [NSMutableArray array];
+    NSMutableArray *fieldNames = [NSMutableArray array];
+    [FLEXHeapEnumerator enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id tryObject, __unsafe_unretained Class actualClass) {
+        // Get all the ivars on the object. Start with the class and and travel up the inheritance chain.
+        // Once we find a match, record it and move on to the next object. There's no reason to find multiple matches within the same object.
+        Class tryClass = actualClass;
+        while (tryClass) {
+            unsigned int ivarCount = 0;
+            Ivar *ivars = class_copyIvarList(tryClass, &ivarCount);
+            for (unsigned int ivarIndex = 0; ivarIndex < ivarCount; ivarIndex++) {
+                Ivar ivar = ivars[ivarIndex];
+                const char *typeEncoding = ivar_getTypeEncoding(ivar);
+                if (typeEncoding[0] == @encode(id)[0] || typeEncoding[0] == @encode(Class)[0]) {
+                    ptrdiff_t offset = ivar_getOffset(ivar);
+                    uintptr_t *fieldPointer = (__bridge void *)tryObject + offset;
+                    if (*fieldPointer == (uintptr_t)(__bridge void *)object) {
+                        [instances addObject:tryObject];
+                        [fieldNames addObject:@(ivar_getName(ivar))];
+                        return;
+                    }
+                }
+            }
+            tryClass = class_getSuperclass(tryClass);
+        }
+    }];
+    FLEXInstancesTableViewController *instancesViewController = [[self alloc] init];
+    instancesViewController.instances = instances;
+    instancesViewController.fieldNames = fieldNames;
+    instancesViewController.title = [NSString stringWithFormat:@"Referencing %@ %p", NSStringFromClass(object_getClass(object)), object];
+    return instancesViewController;
+}
+
 
 #pragma mark - Table View Data Source
 
@@ -64,7 +101,13 @@
     }
     
     id instance = [self.instances objectAtIndex:indexPath.row];
-    cell.textLabel.text = [NSString stringWithFormat:@"%p", instance];
+    NSString *title = nil;
+    if ([self.fieldNames count] > indexPath.row) {
+        title = [NSString stringWithFormat:@"%@ %@", NSStringFromClass(object_getClass(instance)), [self.fieldNames objectAtIndex:indexPath.row]];
+    } else {
+        title = [NSString stringWithFormat:@"%@ %p", NSStringFromClass(object_getClass(instance)), instance];
+    }
+    cell.textLabel.text = title;
     cell.detailTextLabel.text = [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:instance];
     
     return cell;

+ 2 - 1
Classes/Object Explorers/FLEXObjectExplorerViewController.h

@@ -15,7 +15,8 @@ typedef NS_ENUM(NSUInteger, FLEXObjectExplorerSection) {
     FLEXObjectExplorerSectionIvars,
     FLEXObjectExplorerSectionMethods,
     FLEXObjectExplorerSectionClassMethods,
-    FLEXObjectExplorerSectionSuperclasses
+    FLEXObjectExplorerSectionSuperclasses,
+    FLEXObjectExplorerSectionReferencingInstances
 };
 
 @interface FLEXObjectExplorerViewController : UITableViewController

+ 28 - 2
Classes/Object Explorers/FLEXObjectExplorerViewController.m

@@ -14,6 +14,7 @@
 #import "FLEXPropertyEditorViewController.h"
 #import "FLEXIvarEditorViewController.h"
 #import "FLEXMethodCallingViewController.h"
+#import "FLEXInstancesTableViewController.h"
 #import <objc/runtime.h>
 
 // Convenience boxes to keep runtime properties, ivars, and methods in foundation collections.
@@ -499,7 +500,8 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
                              @(FLEXObjectExplorerSectionIvars),
                              @(FLEXObjectExplorerSectionMethods),
                              @(FLEXObjectExplorerSectionClassMethods),
-                             @(FLEXObjectExplorerSectionSuperclasses)];
+                             @(FLEXObjectExplorerSectionSuperclasses),
+                             @(FLEXObjectExplorerSectionReferencingInstances)];
     });
     return possibleSections;
 }
@@ -565,6 +567,10 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
         case FLEXObjectExplorerSectionSuperclasses:
             numberOfRows = [self.filteredSuperclasses count];
             break;
+            
+        case FLEXObjectExplorerSectionReferencingInstances:
+            numberOfRows = 1;
+            break;
     }
     return numberOfRows;
 }
@@ -599,6 +605,11 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
             
         case FLEXObjectExplorerSectionSuperclasses:
             title = NSStringFromClass([self.filteredSuperclasses objectAtIndex:row]);
+            break;
+            
+        case FLEXObjectExplorerSectionReferencingInstances:
+            title = @"Other objects with ivars referencing this object";
+            break;
     }
     return title;
 }
@@ -630,6 +641,9 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
             
         case FLEXObjectExplorerSectionSuperclasses:
             break;
+            
+        case FLEXObjectExplorerSectionReferencingInstances:
+            break;
     }
     return subtitle;
 }
@@ -676,6 +690,10 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
         case FLEXObjectExplorerSectionSuperclasses:
             canDrillIn = YES;
             break;
+            
+        case FLEXObjectExplorerSectionReferencingInstances:
+            canDrillIn = YES;
+            break;
     }
     return canDrillIn;
 }
@@ -727,6 +745,10 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
         case FLEXObjectExplorerSectionSuperclasses: {
             title = [self sectionTitleWithBaseName:@"Superclasses" totalCount:[self.superclasses count] filteredCount:[self.filteredSuperclasses count]];
         } break;
+            
+        case FLEXObjectExplorerSectionReferencingInstances: {
+            title = @"Object Graph";
+        } break;
     }
     return title;
 }
@@ -775,7 +797,11 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
         case FLEXObjectExplorerSectionSuperclasses: {
             Class superclass = [self.filteredSuperclasses objectAtIndex:row];
             viewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:superclass];
-        }
+        } break;
+            
+        case FLEXObjectExplorerSectionReferencingInstances: {
+            viewController = [FLEXInstancesTableViewController instancesTableViewControllerForInstancesReferencingObject:self.object];
+        } break;
     }
     return viewController;
 }