Explorar o código

Refactor object explorers—shortcuts

The root object explorer class now provides a mechanism to easily add property shortcuts in a subclass without a lot of boilerplate. Every shortcut is drillable by default.

Quite a bit of code was lifted out of the view explorer for this.
Tanner Bennett %!s(int64=7) %!d(string=hai) anos
pai
achega
2a34f21667

+ 0 - 5
Classes/ObjectExplorers/Controllers/FLEXArrayExplorerViewController.m

@@ -51,11 +51,6 @@
     return [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:[self detailObjectForRowCookie:rowCookie]];
 }
 
-- (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie
-{
-    return YES;
-}
-
 - (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie
 {
     return [FLEXObjectExplorerFactory explorerViewControllerForObject:[self detailObjectForRowCookie:rowCookie]];

+ 0 - 5
Classes/ObjectExplorers/Controllers/FLEXClassExplorerViewController.m

@@ -88,11 +88,6 @@ typedef NS_ENUM(NSUInteger, FLEXClassExplorerRow) {
     return nil;
 }
 
-- (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie
-{
-    return YES;
-}
-
 - (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie
 {
     UIViewController *drillInViewController = nil;

+ 0 - 9
Classes/ObjectExplorers/Controllers/FLEXColorExplorerViewController.m

@@ -37,13 +37,4 @@
     return square;
 }
 
-//- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
-//    UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
-//    if (indexPath.section == 0 && indexPath.row == 0) {
-//        cell.contentView.backgroundColor = (UIColor *)self.object;
-//    }
-//
-//    return cell;
-//}
-
 @end

+ 0 - 5
Classes/ObjectExplorers/Controllers/FLEXDefaultsExplorerViewController.m

@@ -47,11 +47,6 @@
     return [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:[self.defaults objectForKey:rowCookie]];
 }
 
-- (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie
-{
-    return YES;
-}
-
 - (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie
 {
     UIViewController *drillInViewController = nil;

+ 0 - 5
Classes/ObjectExplorers/Controllers/FLEXDictionaryExplorerViewController.m

@@ -46,11 +46,6 @@
     return [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:self.dictionary[rowCookie]];
 }
 
-- (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie
-{
-    return YES;
-}
-
 - (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie
 {
     return [FLEXObjectExplorerFactory explorerViewControllerForObject:self.dictionary[rowCookie]];

+ 0 - 5
Classes/ObjectExplorers/Controllers/FLEXImageExplorerViewController.m

@@ -52,11 +52,6 @@ typedef NS_ENUM(NSUInteger, FLEXImageExplorerRow) {
     return nil;
 }
 
-- (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie
-{
-    return YES;
-}
-
 - (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie
 {
     UIViewController *drillInViewController = nil;

+ 0 - 5
Classes/ObjectExplorers/Controllers/FLEXLayerExplorerViewController.m

@@ -54,11 +54,6 @@ typedef NS_ENUM(NSUInteger, FLEXLayerExplorerRow) {
     return title;
 }
 
-- (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie
-{
-    return YES;
-}
-
 - (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie
 {
     UIViewController *drillInViewController = nil;

+ 14 - 0
Classes/ObjectExplorers/Controllers/FLEXObjectExplorerViewController.h

@@ -50,3 +50,17 @@ typedef NS_ENUM(NSUInteger, FLEXObjectExplorerSection) {
 - (NSArray *)possibleExplorerSections;
 
 @end
+
+@interface FLEXObjectExplorerViewController (Shortcuts)
+
+/// @brief Names of properties to supply as shortcuts. If this array is empty, no shortcuts are displayed.
+///
+/// @discussion Populating this array in a subclass will make FLEXObjectExplorerViewController show a custom
+/// section with row titles like "@property NSString *foo" and subtitles with their values.
+/// customSectionRowCookies will return this array. Every row in the section is drillable by default.
+///
+/// For an example on how to use the default behavior provided or to override it,
+/// see FLEXViewExplorerViewController
+- (NSArray<NSString *> *)shortcutPropertyNames;
+
+@end

+ 55 - 3
Classes/ObjectExplorers/Controllers/FLEXObjectExplorerViewController.m

@@ -578,6 +578,11 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
     return [FLEXRuntimeUtility prettyNameForMethod:classMethodBox.method isClassMethod:YES];
 }
 
+- (objc_property_t)viewPropertyForName:(NSString *)propertyName
+{
+    return class_getProperty([self.object class], propertyName.UTF8String);
+}
+
 
 #pragma mark - Superclasses
 
@@ -1121,31 +1126,71 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
 
 - (NSString *)customSectionTitle
 {
-    return nil;
+    return self.shortcutPropertyNames.count ? @"Shortcuts" : nil;
 }
 
 - (NSArray *)customSectionRowCookies
 {
-    return nil;
+    return self.shortcutPropertyNames;
 }
 
 - (NSString *)customSectionTitleForRowCookie:(id)rowCookie
 {
+    if ([rowCookie isKindOfClass:[NSString class]]) {
+        objc_property_t property = [self viewPropertyForName:rowCookie];
+        if (property) {
+            NSString *prettyPropertyName = [FLEXRuntimeUtility prettyNameForProperty:property];
+            // Since we're outside of the "properties" section, prepend @property for clarity.
+            return [@"@property " stringByAppendingString:prettyPropertyName];
+        } else if ([rowCookie respondsToSelector:@selector(description)]) {
+            return [@"No property found for object: " stringByAppendingString:[rowCookie description]];
+        } else {
+            NSString *cls = NSStringFromClass([rowCookie class]);
+            return [@"No property found for object of class " stringByAppendingString:cls];
+        }
+    }
+
     return nil;
 }
 
 - (NSString *)customSectionSubtitleForRowCookie:(id)rowCookie
 {
+    if ([rowCookie isKindOfClass:[NSString class]]) {
+        objc_property_t property = [self viewPropertyForName:rowCookie];
+        if (property) {
+            id value = [FLEXRuntimeUtility valueForProperty:property onObject:self.object];
+            return [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:value];
+        } else {
+            return nil;
+        }
+    }
+
     return nil;
 }
 
 - (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie
 {
-    return NO;
+    return YES;
 }
 
 - (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie
 {
+    if ([rowCookie isKindOfClass:[NSString class]]) {
+        objc_property_t property = [self viewPropertyForName:rowCookie];
+        if (property) {
+            id currentValue = [FLEXRuntimeUtility valueForProperty:property onObject:self.object];
+            if ([FLEXPropertyEditorViewController canEditProperty:property onObject:self.object currentValue:currentValue]) {
+                return [[FLEXPropertyEditorViewController alloc] initWithTarget:self.object property:property];
+            } else {
+                return [FLEXObjectExplorerFactory explorerViewControllerForObject:currentValue];
+            }
+        } else {
+            [NSException raise:NSInternalInconsistencyException
+                        format:@"Cannot drill into row for cookie: %@", rowCookie];
+            return nil;
+        }
+    }
+
     return nil;
 }
 
@@ -1170,3 +1215,10 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
 }
 
 @end
+
+
+@implementation FLEXObjectExplorerViewController (Shortcuts)
+
+- (NSArray<NSString *> *)shortcutPropertyNames { return @[]; }
+
+@end

+ 0 - 5
Classes/ObjectExplorers/Controllers/FLEXSetExplorerViewController.m

@@ -46,11 +46,6 @@
     return nil;
 }
 
-- (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie
-{
-    return YES;
-}
-
 - (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie
 {
     return [FLEXObjectExplorerFactory explorerViewControllerForObject:rowCookie];

+ 1 - 1
Classes/ObjectExplorers/Controllers/FLEXViewControllerExplorerViewController.m

@@ -76,7 +76,7 @@ typedef NS_ENUM(NSUInteger, FLEXViewControllerExplorerRow) {
     BOOL canDrillIn = NO;
     if ([rowCookie isEqual:@(FLEXViewControllerExplorerRowPush)]) {
         canDrillIn = [self canPushViewController];
-    }else if ([rowCookie isEqual:@(FLEXViewControllerExplorerRowView)]) {
+    } else if ([rowCookie isEqual:@(FLEXViewControllerExplorerRowView)]) {
         canDrillIn = self.viewController.view != nil;
     }
     return canDrillIn;

+ 7 - 32
Classes/ObjectExplorers/Controllers/FLEXViewExplorerViewController.m

@@ -52,14 +52,16 @@ typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
     }
     
     [rowCookies addObject:@(FLEXViewExplorerRowPreview)];
-    [rowCookies addObjectsFromArray:[self shortcutPropertyNames]];
+    [rowCookies addObjectsFromArray:[super customSectionRowCookies]];
     
     return rowCookies;
 }
 
 - (NSArray<NSString *> *)shortcutPropertyNames
 {
-    NSArray<NSString *> *propertyNames = @[@"frame", @"bounds", @"center", @"transform", @"backgroundColor", @"alpha", @"opaque", @"hidden", @"clipsToBounds", @"userInteractionEnabled", @"layer"];
+    NSArray *propertyNames = @[@"frame", @"bounds", @"center", @"transform",
+                               @"backgroundColor", @"alpha", @"opaque", @"hidden",
+                               @"clipsToBounds", @"userInteractionEnabled", @"layer"];
     
     if ([self.viewToExplore isKindOfClass:[UILabel class]]) {
         propertyNames = [@[@"text", @"font", @"textColor"] arrayByAddingObjectsFromArray:propertyNames];
@@ -88,12 +90,7 @@ typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
                 break;
         }
     } else if ([rowCookie isKindOfClass:[NSString class]]) {
-        objc_property_t property = [self viewPropertyForName:rowCookie];
-        if (property) {
-            NSString *prettyPropertyName = [FLEXRuntimeUtility prettyNameForProperty:property];
-            // Since we're outside of the "properties" section, prepend @property for clarity.
-            title = [NSString stringWithFormat:@"@property %@", prettyPropertyName];
-        }
+        title = [super customSectionTitleForRowCookie:rowCookie];
     }
     
     return title;
@@ -118,26 +115,12 @@ typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
                 break;
         }
     } else if ([rowCookie isKindOfClass:[NSString class]]) {
-        objc_property_t property = [self viewPropertyForName:rowCookie];
-        if (property) {
-            id value = [FLEXRuntimeUtility valueForProperty:property onObject:self.viewToExplore];
-            subtitle = [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:value];
-        }
+        return [super customSectionSubtitleForRowCookie:rowCookie];
     }
     
     return subtitle;
 }
 
-- (objc_property_t)viewPropertyForName:(NSString *)propertyName
-{
-    return class_getProperty([self.viewToExplore class], [propertyName UTF8String]);
-}
-
-- (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie
-{
-    return YES;
-}
-
 - (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie
 {
     UIViewController *drillInViewController = nil;
@@ -158,15 +141,7 @@ typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
                 break;
         }
     } else if ([rowCookie isKindOfClass:[NSString class]]) {
-        objc_property_t property = [self viewPropertyForName:rowCookie];
-        if (property) {
-            id currentValue = [FLEXRuntimeUtility valueForProperty:property onObject:self.viewToExplore];
-            if ([FLEXPropertyEditorViewController canEditProperty:property onObject:self.viewToExplore currentValue:currentValue]) {
-                drillInViewController = [[FLEXPropertyEditorViewController alloc] initWithTarget:self.object property:property];
-            } else {
-                drillInViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:currentValue];
-            }
-        }
+        return [super customSectionDrillInViewControllerForRowCookie:rowCookie];
     }
 
     return drillInViewController;

+ 1 - 0
Classes/Utility/FLEXUtility.h

@@ -34,6 +34,7 @@
 + (NSString *)applicationImageName;
 + (NSString *)applicationName;
 + (NSString *)safeDescriptionForObject:(id)object;
++ (NSString *)safeDebugDescriptionForObject:(id)object;
 + (NSString *)addressOfObject:(id)object;
 + (UIFont *)defaultFontOfSize:(CGFloat)size;
 + (UIFont *)defaultTableViewCellLabelFont;

+ 15 - 0
Classes/Utility/FLEXUtility.m

@@ -127,6 +127,21 @@
     return description;
 }
 
++ (NSString *)safeDebugDescriptionForObject:(id)object
+{
+    NSString *description = [self safeDescriptionForObject:object];
+    if (!description) {
+        NSString *cls = NSStringFromClass(object_getClass(object));
+        if (object_isClass(object)) {
+            description = [cls stringByAppendingString:@" class (no description)"];
+       } else {
+           description = [cls stringByAppendingString:@" instance (no description)"];
+       }
+    }
+
+    return description;
+}
+
 + (NSString *)addressOfObject:(id)object
 {
     return [NSString stringWithFormat:@"%p", object];