mirror of
				https://github.com/SoPat712/YTLitePlus.git
				synced 2025-10-30 20:34:03 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			251 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
			
		
		
	
	
			251 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
| //
 | |
| //  FLEXObjectListViewController.m
 | |
| //  Flipboard
 | |
| //
 | |
| //  Created by Ryan Olson on 5/28/14.
 | |
| //  Copyright (c) 2020 FLEX Team. All rights reserved.
 | |
| //
 | |
| 
 | |
| #import "FLEXObjectListViewController.h"
 | |
| #import "FLEXObjectExplorerFactory.h"
 | |
| #import "FLEXObjectExplorerViewController.h"
 | |
| #import "FLEXMutableListSection.h"
 | |
| #import "FLEXRuntimeUtility.h"
 | |
| #import "FLEXUtility.h"
 | |
| #import "FLEXHeapEnumerator.h"
 | |
| #import "FLEXObjectRef.h"
 | |
| #import "NSString+FLEX.h"
 | |
| #import "NSObject+FLEX_Reflection.h"
 | |
| #import "FLEXTableViewCell.h"
 | |
| #import <malloc/malloc.h>
 | |
| 
 | |
| 
 | |
| typedef NS_ENUM(NSUInteger, FLEXObjectReferenceSection) {
 | |
|     FLEXObjectReferenceSectionMain,
 | |
|     FLEXObjectReferenceSectionAutoLayout,
 | |
|     FLEXObjectReferenceSectionKVO,
 | |
|     FLEXObjectReferenceSectionFLEX,
 | |
|     
 | |
|     FLEXObjectReferenceSectionCount
 | |
| };
 | |
| 
 | |
| @interface FLEXObjectListViewController ()
 | |
| 
 | |
| @property (nonatomic, readonly, class) NSArray<NSPredicate *> *defaultPredicates;
 | |
| @property (nonatomic, readonly, class) NSArray<NSString *> *defaultSectionTitles;
 | |
| 
 | |
| 
 | |
| @property (nonatomic, copy) NSArray<FLEXMutableListSection *> *sections;
 | |
| @property (nonatomic, copy) NSArray<FLEXMutableListSection *> *allSections;
 | |
| 
 | |
| @property (nonatomic, readonly, nullable) NSArray<FLEXObjectRef *> *references;
 | |
| @property (nonatomic, readonly) NSArray<NSPredicate *> *predicates;
 | |
| @property (nonatomic, readonly) NSArray<NSString *> *sectionTitles;
 | |
| 
 | |
| @end
 | |
| 
 | |
| @implementation FLEXObjectListViewController
 | |
| @dynamic sections, allSections;
 | |
| 
 | |
| #pragma mark - Reference Grouping
 | |
| 
 | |
| + (NSPredicate *)defaultPredicateForSection:(NSInteger)section {
 | |
|     // These are the types of references that we typically don't care about.
 | |
|     // We want this list of "object-ivar pairs" split into two sections.
 | |
|     BOOL(^isKVORelated)(FLEXObjectRef *, NSDictionary *) = ^BOOL(FLEXObjectRef *ref, NSDictionary *bindings) {
 | |
|         NSString *row = ref.reference;
 | |
|         return [row isEqualToString:@"__NSObserver object"] ||
 | |
|                [row isEqualToString:@"_CFXNotificationObjcObserverRegistration _object"];
 | |
|     };
 | |
| 
 | |
|     /// These are common AutoLayout related references we also rarely care about.
 | |
|     BOOL(^isConstraintRelated)(FLEXObjectRef *, NSDictionary *) = ^BOOL(FLEXObjectRef *ref, NSDictionary *bindings) {
 | |
|         static NSSet *ignored = nil;
 | |
|         static dispatch_once_t onceToken;
 | |
|         dispatch_once(&onceToken, ^{
 | |
|             ignored = [NSSet setWithArray:@[
 | |
|                 @"NSLayoutConstraint _container",
 | |
|                 @"NSContentSizeLayoutConstraint _container",
 | |
|                 @"NSAutoresizingMaskLayoutConstraint _container",
 | |
|                 @"MASViewConstraint _installedView",
 | |
|                 @"MASLayoutConstraint _container",
 | |
|                 @"MASViewAttribute _view"
 | |
|             ]];
 | |
|         });
 | |
| 
 | |
|         NSString *row = ref.reference;
 | |
|         return ([row hasPrefix:@"NSLayout"] && [row hasSuffix:@" _referenceItem"]) ||
 | |
|                ([row hasPrefix:@"NSIS"] && [row hasSuffix:@" _delegate"])  ||
 | |
|                ([row hasPrefix:@"_NSAutoresizingMask"] && [row hasSuffix:@" _referenceItem"]) ||
 | |
|                [ignored containsObject:row];
 | |
|     };
 | |
|     
 | |
|     /// These are FLEX classes and usually you aren't looking for FLEX references inside FLEX itself
 | |
|     BOOL(^isFLEXClass)(FLEXObjectRef *, NSDictionary *) = ^BOOL(FLEXObjectRef *ref, NSDictionary *bindings) {
 | |
|         return [ref.reference hasPrefix:@"FLEX"];
 | |
|     };
 | |
| 
 | |
|     BOOL(^isEssential)(FLEXObjectRef *, NSDictionary *) = ^BOOL(FLEXObjectRef *ref, NSDictionary *bindings) {
 | |
|         return !(
 | |
|             isKVORelated(ref, bindings) ||
 | |
|             isConstraintRelated(ref, bindings) ||
 | |
|             isFLEXClass(ref, bindings)
 | |
|         );
 | |
|     };
 | |
| 
 | |
|     switch (section) {
 | |
|         case FLEXObjectReferenceSectionMain:
 | |
|             return [NSPredicate predicateWithBlock:isEssential];
 | |
|         case FLEXObjectReferenceSectionAutoLayout:
 | |
|             return [NSPredicate predicateWithBlock:isConstraintRelated];
 | |
|         case FLEXObjectReferenceSectionKVO:
 | |
|             return [NSPredicate predicateWithBlock:isKVORelated];
 | |
|         case FLEXObjectReferenceSectionFLEX:
 | |
|             return [NSPredicate predicateWithBlock:isFLEXClass];
 | |
| 
 | |
|         default: return nil;
 | |
|     }
 | |
| }
 | |
| 
 | |
| + (NSArray<NSPredicate *> *)defaultPredicates {
 | |
|     return [NSArray flex_forEachUpTo:FLEXObjectReferenceSectionCount map:^id(NSUInteger i) {
 | |
|         return [self defaultPredicateForSection:i];
 | |
|     }];
 | |
| }
 | |
| 
 | |
| + (NSArray<NSString *> *)defaultSectionTitles {
 | |
|     return @[
 | |
|         @"", @"AutoLayout", @"Key-Value Observing", @"FLEX"
 | |
|     ];
 | |
| }
 | |
| 
 | |
| 
 | |
| #pragma mark - Initialization
 | |
| 
 | |
| - (id)initWithReferences:(nullable NSArray<FLEXObjectRef *> *)references {
 | |
|     return [self initWithReferences:references predicates:nil sectionTitles:nil];
 | |
| }
 | |
| 
 | |
| - (id)initWithReferences:(NSArray<FLEXObjectRef *> *)references
 | |
|               predicates:(NSArray<NSPredicate *> *)predicates
 | |
|            sectionTitles:(NSArray<NSString *> *)sectionTitles {
 | |
|     NSParameterAssert(predicates.count == sectionTitles.count);
 | |
| 
 | |
|     self = [super initWithStyle:UITableViewStylePlain];
 | |
|     if (self) {
 | |
|         _references = references;
 | |
|         _predicates = predicates;
 | |
|         _sectionTitles = sectionTitles;
 | |
|     }
 | |
| 
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| + (UIViewController *)instancesOfClassWithName:(NSString *)className retained:(BOOL)retain {
 | |
|     NSArray<FLEXObjectRef *> *references = [FLEXHeapEnumerator
 | |
|         instancesOfClassWithName:className retained:retain
 | |
|     ];
 | |
|     
 | |
|     if (references.count == 1) {
 | |
|         return [FLEXObjectExplorerFactory
 | |
|             explorerViewControllerForObject:references.firstObject.object
 | |
|         ];
 | |
|     }
 | |
| 
 | |
|     FLEXObjectListViewController *controller = [[self alloc] initWithReferences:references];
 | |
|     controller.title = [NSString stringWithFormat:@"%@ (%@)", className, @(references.count)];
 | |
|     return controller;
 | |
| }
 | |
| 
 | |
| + (instancetype)subclassesOfClassWithName:(NSString *)className {
 | |
|     NSArray<FLEXObjectRef *> *references = [FLEXHeapEnumerator subclassesOfClassWithName:className];
 | |
|     FLEXObjectListViewController *controller = [[self alloc] initWithReferences:references];
 | |
|     controller.title = [NSString stringWithFormat:@"Subclasses of %@ (%@)",
 | |
|         className, @(references.count)
 | |
|     ];
 | |
| 
 | |
|     return controller;
 | |
| }
 | |
| 
 | |
| + (instancetype)objectsWithReferencesToObject:(id)object retained:(BOOL)retain {
 | |
|     static Class SwiftObjectClass = nil;
 | |
|     static dispatch_once_t onceToken;
 | |
|     dispatch_once(&onceToken, ^{
 | |
|         SwiftObjectClass = NSClassFromString(@"SwiftObject");
 | |
|         if (!SwiftObjectClass) {
 | |
|             SwiftObjectClass = NSClassFromString(@"Swift._SwiftObject");
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     NSArray<FLEXObjectRef *> *instances = [FLEXHeapEnumerator
 | |
|         objectsWithReferencesToObject:object retained:retain
 | |
|     ];
 | |
| 
 | |
|     FLEXObjectListViewController *viewController = [[self alloc]
 | |
|         initWithReferences:instances
 | |
|         predicates:self.defaultPredicates
 | |
|         sectionTitles:self.defaultSectionTitles
 | |
|     ];
 | |
|     viewController.title = [NSString stringWithFormat:@"Referencing %@ %p",
 | |
|         [FLEXRuntimeUtility safeClassNameForObject:object], object
 | |
|     ];
 | |
|     return viewController;
 | |
| }
 | |
| 
 | |
| 
 | |
| #pragma mark - Overrides
 | |
| 
 | |
| - (void)viewDidLoad {
 | |
|     [super viewDidLoad];
 | |
| 
 | |
|     self.showsSearchBar = YES;
 | |
| }
 | |
| 
 | |
| - (NSArray<FLEXMutableListSection *> *)makeSections {
 | |
|     if (self.predicates.count) {
 | |
|         return [self buildSections:self.sectionTitles predicates:self.predicates];
 | |
|     } else {
 | |
|         return @[[self makeSection:self.references title:nil]];
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| #pragma mark - Private
 | |
| 
 | |
| - (NSArray *)buildSections:(NSArray<NSString *> *)titles predicates:(NSArray<NSPredicate *> *)predicates {
 | |
|     NSParameterAssert(titles.count == predicates.count);
 | |
|     NSParameterAssert(titles); NSParameterAssert(predicates);
 | |
| 
 | |
|     return [NSArray flex_forEachUpTo:titles.count map:^id(NSUInteger i) {
 | |
|         NSArray *rows = [self.references filteredArrayUsingPredicate:predicates[i]];
 | |
|         return [self makeSection:rows title:titles[i]];
 | |
|     }];
 | |
| }
 | |
| 
 | |
| - (FLEXMutableListSection *)makeSection:(NSArray *)rows title:(NSString *)title {
 | |
|     FLEXMutableListSection *section = [FLEXMutableListSection list:rows
 | |
|         cellConfiguration:^(FLEXTableViewCell *cell, FLEXObjectRef *ref, NSInteger row) {
 | |
|             cell.textLabel.text = ref.reference;
 | |
|             cell.detailTextLabel.text = ref.summary;
 | |
|             cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
 | |
|         } filterMatcher:^BOOL(NSString *filterText, FLEXObjectRef *ref) {
 | |
|             if (ref.summary && [ref.summary localizedCaseInsensitiveContainsString:filterText]) {
 | |
|                 return YES;
 | |
|             }
 | |
| 
 | |
|             return [ref.reference localizedCaseInsensitiveContainsString:filterText];
 | |
|         }
 | |
|     ];
 | |
| 
 | |
|     section.selectionHandler = ^(UIViewController *host, FLEXObjectRef *ref) {
 | |
|         [host.navigationController pushViewController:[
 | |
|             FLEXObjectExplorerFactory explorerViewControllerForObject:ref.object
 | |
|         ] animated:YES];
 | |
|     };
 | |
| 
 | |
|     section.customTitle = title;
 | |
|     return section;
 | |
| }
 | |
| 
 | |
| @end
 | 
