Преглед на файлове

Add option to reveal overridden methods

- Publish certain preference changes with NSNotificationCenter so as to update all screens observing these changes
- Observe these preferences in appropriate screens
Tanner Bennett преди 6 години
родител
ревизия
7f119ba0cc

+ 17 - 3
Classes/ObjectExplorers/FLEXObjectExplorer.m

@@ -96,8 +96,9 @@
     [self reloadClassHierarchy];
     
     NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
-    BOOL hideBackingIvars = defaults.flex_explorerHidesRedundantIvars;
-    BOOL hidePropertyMethods = defaults.flex_explorerHidesRedundantMethods;
+    BOOL hideBackingIvars = defaults.flex_explorerHidesPropertyIvars;
+    BOOL hidePropertyMethods = defaults.flex_explorerHidesPropertyMethods;
+    BOOL showMethodOverrides = defaults.flex_explorerShowsMethodOverrides;
 
     // Loop over each class and each superclass, collect
     // the fresh and unique metadata in each category
@@ -112,31 +113,37 @@
             metadataUniquedByName:[cls flex_allInstanceProperties]
             superclass:superclass
             kind:FLEXMetadataKindProperties
+            skip:showMethodOverrides
         ]];
         [_allClassProperties addObject:[self
             metadataUniquedByName:[cls flex_allClassProperties]
             superclass:superclass
             kind:FLEXMetadataKindClassProperties
+            skip:showMethodOverrides
         ]];
         [_allIvars addObject:[self
             metadataUniquedByName:[cls flex_allIvars]
             superclass:nil
             kind:FLEXMetadataKindIvars
+            skip:NO
         ]];
         [_allMethods addObject:[self
             metadataUniquedByName:[cls flex_allInstanceMethods]
             superclass:superclass
             kind:FLEXMetadataKindMethods
+            skip:showMethodOverrides
         ]];
         [_allClassMethods addObject:[self
             metadataUniquedByName:[cls flex_allClassMethods]
             superclass:superclass
             kind:FLEXMetadataKindClassMethods
+            skip:showMethodOverrides
         ]];
         [_allConformedProtocols addObject:[self
             metadataUniquedByName:[cls flex_protocols]
             superclass:superclass
             kind:FLEXMetadataKindProtocols
+            skip:NO
         ]];
         
         // TODO: join instance size, image name, and class hierarchy into a single model object
@@ -233,7 +240,14 @@
 /// Accepts an array of flex metadata objects and discards objects
 /// with duplicate names, as well as properties and methods which
 /// aren't "new" (i.e. those which the superclass responds to)
-- (NSArray *)metadataUniquedByName:(NSArray *)list superclass:(Class)superclass kind:(FLEXMetadataKind)kind {
+- (NSArray *)metadataUniquedByName:(NSArray *)list
+                        superclass:(Class)superclass
+                              kind:(FLEXMetadataKind)kind
+                              skip:(BOOL)skip {
+    if (skip) {
+        return list;
+    }
+    
     // Remove items with same name and return filtered list
     NSMutableSet *names = [NSMutableSet new];
     return [list flex_filtered:^BOOL(id obj, NSUInteger idx) {

+ 51 - 22
Classes/ObjectExplorers/FLEXObjectExplorerViewController.m

@@ -33,6 +33,8 @@
 @property (nonatomic, readonly) FLEXTableViewSection *customSection;
 @property (nonatomic) NSIndexSet *customSectionVisibleIndexes;
 
+@property (nonatomic, readonly) NSArray<NSString *> *observedNotifications;
+
 @end
 
 @implementation FLEXObjectExplorerViewController
@@ -66,6 +68,14 @@
     return self;
 }
 
+- (NSArray<NSString *> *)observedNotifications {
+    return @[
+        kFLEXDefaultsHidePropertyIvarsKey,
+        kFLEXDefaultsHidePropertyMethodsKey,
+        kFLEXDefaultsHideMethodOverridesKey,
+    ];
+}
+
 #pragma mark - View controller lifecycle
 
 - (void)viewDidLoad {
@@ -107,6 +117,24 @@
     rightSwipe.delegate = self;
     [self.tableView addGestureRecognizer:leftSwipe];
     [self.tableView addGestureRecognizer:rightSwipe];
+    
+    // Observe preferences which may change on other screens
+    //
+    // "If your app targets iOS 9.0 and later or macOS 10.11 and later,
+    // you don't need to unregister an observer in its dealloc method."
+    NSArray<NSString *> *observedNotifications = @[
+        kFLEXDefaultsHidePropertyIvarsKey,
+        kFLEXDefaultsHidePropertyMethodsKey,
+        kFLEXDefaultsHideMethodOverridesKey,
+    ];
+    for (NSString *pref in observedNotifications) {
+        [NSNotificationCenter.defaultCenter
+            addObserver:self
+            selector:@selector(fullyReloadData)
+            name:pref
+            object:nil
+        ];
+    }
 }
 
 - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {
@@ -263,32 +291,33 @@
     
 - (void)moreButtonPressed {
     NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
-    BOOL currentlyShowsRedundantIvars = !defaults.flex_explorerHidesRedundantIvars;
-    BOOL currentlyShowsRedundantMethods = !defaults.flex_explorerHidesRedundantMethods;
+    // Maps preference keys to a description of what they affect
+    NSDictionary<NSString *, NSString *> *explorerToggles = @{
+        kFLEXDefaultsHidePropertyIvarsKey:   @"Property-Backing Ivars",
+        kFLEXDefaultsHidePropertyMethodsKey: @"Property-Backing Methods",
+        kFLEXDefaultsHideMethodOverridesKey: @"Method Overrides",
+    };
+    
+    // Maps the key of the action itself to a map of a description
+    // of the action ("hide X") mapped to the current state.
+    //
+    // So keys that are hidden by default have NO mapped to "Show"
+    NSDictionary<NSString *, NSDictionary *> *nextStateDescriptions = @{
+        kFLEXDefaultsHidePropertyIvarsKey:   @{ @NO: @"Hide ", @YES: @"Show " },
+        kFLEXDefaultsHidePropertyMethodsKey: @{ @NO: @"Hide ", @YES: @"Show " },
+        kFLEXDefaultsHideMethodOverridesKey: @{ @NO: @"Show ", @YES: @"Hide " },
+    };
     
     [FLEXAlert makeSheet:^(FLEXAlert *make) {
         make.title(@"Options");
         
-        if (currentlyShowsRedundantIvars) {
-            make.button(@"Hide Property-Backing Ivars").handler(^(NSArray<NSString *> *strings) {
-                defaults.flex_explorerHidesRedundantIvars = YES;
-                [self fullyReloadData];
-            });
-        } else {
-            make.button(@"Show Property-Backing Ivars").handler(^(NSArray<NSString *> *strings) {
-                defaults.flex_explorerHidesRedundantIvars = NO;
-                [self fullyReloadData];
-            });
-        }
-        
-        if (currentlyShowsRedundantMethods) {
-            make.button(@"Hide Property-Backing Methods").handler(^(NSArray<NSString *> *strings) {
-                defaults.flex_explorerHidesRedundantMethods = YES;
-                [self fullyReloadData];
-            });
-        } else {
-            make.button(@"Show Property-Backing Methods").handler(^(NSArray<NSString *> *strings) {
-                defaults.flex_explorerHidesRedundantMethods = NO;
+        for (NSString *option in explorerToggles.allKeys) {
+            BOOL current = [defaults boolForKey:option];
+            NSString *title = [nextStateDescriptions[option][@(current)]
+                stringByAppendingString:explorerToggles[option]
+            ];
+            make.button(title).handler(^(NSArray<NSString *> *strings) {
+                [NSUserDefaults.standardUserDefaults toggleBoolForKey:option];
                 [self fullyReloadData];
             });
         }

+ 16 - 2
Classes/Utility/Categories/NSUserDefaults+FLEX.h

@@ -8,13 +8,27 @@
 
 #import <Foundation/Foundation.h>
 
+// Only use these if the getters and setters aren't good enough for whatever reaso
+extern NSString * const kFLEXDefaultsToolbarTopMarginKey;
+extern NSString * const kFLEXDefaultsiOSPersistentOSLogKey;
+extern NSString * const kFLEXDefaultsHidePropertyIvarsKey;
+extern NSString * const kFLEXDefaultsHidePropertyMethodsKey;
+extern NSString * const kFLEXDefaultsHideMethodOverridesKey;
+
 @interface NSUserDefaults (FLEX)
 
+- (void)toggleBoolForKey:(NSString *)key;
+
 @property (nonatomic) double flex_toolbarTopMargin;
 
+/// NO by default
 @property (nonatomic) BOOL flex_cacheOSLogMessages;
 
-@property (nonatomic) BOOL flex_explorerHidesRedundantIvars;
-@property (nonatomic) BOOL flex_explorerHidesRedundantMethods;
+/// NO by default
+@property (nonatomic) BOOL flex_explorerHidesPropertyIvars;
+/// NO by default
+@property (nonatomic) BOOL flex_explorerHidesPropertyMethods;
+/// NO by default
+@property (nonatomic) BOOL flex_explorerShowsMethodOverrides;
 
 @end

+ 47 - 17
Classes/Utility/Categories/NSUserDefaults+FLEX.m

@@ -8,47 +8,77 @@
 
 #import "NSUserDefaults+FLEX.h"
 
-static NSString * const kFLEXToolbarTopMarginKey = @"com.flex.FLEXToolbar.topMargin";
-static NSString * const kFLEXHideRedundantIvarsKey = @"com.flipboard.FLEX.hide_redundant_ivars";
-static NSString * const kFLEXHideRedundantMethodsKey = @"com.flipboard.FLEX.hide_redundant_methods";
-static NSString * const kFLEXiOSPersistentOSLogKey = @"com.flipborad.flex.enable_persistent_os_log";
+NSString * const kFLEXDefaultsToolbarTopMarginKey = @"com.flex.FLEXToolbar.topMargin";
+NSString * const kFLEXDefaultsiOSPersistentOSLogKey = @"com.flipborad.flex.enable_persistent_os_log";
+NSString * const kFLEXDefaultsHidePropertyIvarsKey = @"com.flipboard.FLEX.hide_property_ivars";
+NSString * const kFLEXDefaultsHidePropertyMethodsKey = @"com.flipboard.FLEX.hide_property_methods";
+NSString * const kFLEXDefaultsHideMethodOverridesKey = @"com.flipboard.FLEX.hide_method_overrides";
 
 @implementation NSUserDefaults (FLEX)
 
+- (void)toggleBoolForKey:(NSString *)key {
+    [self setBool:![self boolForKey:key] forKey:key];
+    [NSNotificationCenter.defaultCenter postNotificationName:key object:nil];
+}
+
 - (double)flex_toolbarTopMargin {
-    if ([self objectForKey:kFLEXToolbarTopMarginKey]) {
-        return [self doubleForKey:kFLEXToolbarTopMarginKey];
+    if ([self objectForKey:kFLEXDefaultsToolbarTopMarginKey]) {
+        return [self doubleForKey:kFLEXDefaultsToolbarTopMarginKey];
     }
     
     return 100;
 }
 
 - (void)setFlex_toolbarTopMargin:(double)margin {
-    [self setDouble:margin forKey:kFLEXToolbarTopMarginKey];
+    [self setDouble:margin forKey:kFLEXDefaultsToolbarTopMarginKey];
 }
 
 - (BOOL)flex_cacheOSLogMessages {
-    return [self boolForKey:kFLEXiOSPersistentOSLogKey];
+    return [self boolForKey:kFLEXDefaultsiOSPersistentOSLogKey];
 }
 
 - (void)setFlex_cacheOSLogMessages:(BOOL)cache {
-    [self setBool:cache forKey:kFLEXiOSPersistentOSLogKey];
+    [self setBool:cache forKey:kFLEXDefaultsiOSPersistentOSLogKey];
+    [NSNotificationCenter.defaultCenter
+        postNotificationName:kFLEXDefaultsiOSPersistentOSLogKey
+        object:nil
+    ];
+}
+
+- (BOOL)flex_explorerHidesPropertyIvars {
+    return [self boolForKey:kFLEXDefaultsHidePropertyIvarsKey];
+}
+
+- (void)setFlex_explorerHidesPropertyIvars:(BOOL)hide {
+    [self setBool:hide forKey:kFLEXDefaultsHidePropertyIvarsKey];
+    [NSNotificationCenter.defaultCenter
+        postNotificationName:kFLEXDefaultsHidePropertyIvarsKey
+        object:nil
+    ];
 }
 
-- (BOOL)flex_explorerHidesRedundantIvars {
-    return [self boolForKey:kFLEXHideRedundantIvarsKey];
+- (BOOL)flex_explorerHidesPropertyMethods {
+    return [self boolForKey:kFLEXDefaultsHidePropertyMethodsKey];
 }
 
-- (void)setFlex_explorerHidesRedundantIvars:(BOOL)hide {
-    [self setBool:hide forKey:kFLEXHideRedundantIvarsKey];
+- (void)setFlex_explorerHidesPropertyMethods:(BOOL)hide {
+    [self setBool:hide forKey:kFLEXDefaultsHidePropertyMethodsKey];
+    [NSNotificationCenter.defaultCenter
+        postNotificationName:kFLEXDefaultsHidePropertyMethodsKey
+        object:nil
+    ];
 }
 
-- (BOOL)flex_explorerHidesRedundantMethods {
-    return [self boolForKey:kFLEXHideRedundantMethodsKey];
+- (BOOL)flex_explorerShowsMethodOverrides {
+    return [self boolForKey:kFLEXDefaultsHideMethodOverridesKey];
 }
 
-- (void)setFlex_explorerHidesRedundantMethods:(BOOL)hide {
-    [self setBool:hide forKey:kFLEXHideRedundantMethodsKey];
+- (void)setFlex_explorerShowsMethodOverrides:(BOOL)show {
+    [self setBool:show forKey:kFLEXDefaultsHideMethodOverridesKey];
+    [NSNotificationCenter.defaultCenter
+        postNotificationName:kFLEXDefaultsHideMethodOverridesKey
+        object:nil
+    ];
 }
 
 @end