123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- //
- // FLEXObjectExplorerFactory.m
- // Flipboard
- //
- // Created by Ryan Olson on 5/15/14.
- // Copyright (c) 2020 FLEX Team. All rights reserved.
- //
- #import "FLEXObjectExplorerFactory.h"
- #import "FLEXGlobalsViewController.h"
- #import "FLEXClassShortcuts.h"
- #import "FLEXViewShortcuts.h"
- #import "FLEXViewControllerShortcuts.h"
- #import "FLEXUIAppShortcuts.h"
- #import "FLEXImageShortcuts.h"
- #import "FLEXLayerShortcuts.h"
- #import "FLEXColorPreviewSection.h"
- #import "FLEXDefaultsContentSection.h"
- #import "FLEXBundleShortcuts.h"
- #import "FLEXBlockShortcuts.h"
- #import "FLEXUtility.h"
- @implementation FLEXObjectExplorerFactory
- static NSMutableDictionary<id<NSCopying>, Class> *classesToRegisteredSections = nil;
- + (void)initialize {
- if (self == [FLEXObjectExplorerFactory class]) {
- // DO NOT USE STRING KEYS HERE
- // We NEED to use the class as a key, because we CANNOT
- // differentiate a class's name from the metaclass's name.
- // These mappings are per-class-object, not per-class-name.
- //
- // For example, if we used class names, this would result in
- // the object explorer trying to render a color preview for
- // the UIColor class object, which is not a color itself.
- #define ClassKey(name) (id<NSCopying>)[name class]
- #define ClassKeyByName(str) (id<NSCopying>)NSClassFromString(@ #str)
- #define MetaclassKey(meta) (id<NSCopying>)object_getClass([meta class])
- classesToRegisteredSections = [NSMutableDictionary dictionaryWithDictionary:@{
- MetaclassKey(NSObject) : [FLEXClassShortcuts class],
- ClassKey(NSArray) : [FLEXCollectionContentSection class],
- ClassKey(NSSet) : [FLEXCollectionContentSection class],
- ClassKey(NSDictionary) : [FLEXCollectionContentSection class],
- ClassKey(NSOrderedSet) : [FLEXCollectionContentSection class],
- ClassKey(NSUserDefaults) : [FLEXDefaultsContentSection class],
- ClassKey(UIViewController) : [FLEXViewControllerShortcuts class],
- ClassKey(UIApplication) : [FLEXUIAppShortcuts class],
- ClassKey(UIView) : [FLEXViewShortcuts class],
- ClassKey(UIImage) : [FLEXImageShortcuts class],
- ClassKey(CALayer) : [FLEXLayerShortcuts class],
- ClassKey(UIColor) : [FLEXColorPreviewSection class],
- ClassKey(NSBundle) : [FLEXBundleShortcuts class],
- ClassKeyByName(NSBlock) : [FLEXBlockShortcuts class],
- }];
- #undef ClassKey
- #undef ClassKeyByName
- #undef MetaclassKey
- }
- }
- + (FLEXObjectExplorerViewController *)explorerViewControllerForObject:(id)object {
- // Can't explore nil
- if (!object) {
- return nil;
- }
- // If we're given an object, this will look up it's class hierarchy
- // until it finds a registration. This will work for KVC classes,
- // since they are children of the original class, and not siblings.
- // If we are given an object, object_getClass will return a metaclass,
- // and the same thing will happen. FLEXClassShortcuts is the default
- // shortcut section for NSObject.
- //
- // TODO: rename it to FLEXNSObjectShortcuts or something?
- Class sectionClass = nil;
- Class cls = object_getClass(object);
- do {
- sectionClass = classesToRegisteredSections[(id<NSCopying>)cls];
- } while (!sectionClass && (cls = [cls superclass]));
- if (!sectionClass) {
- sectionClass = [FLEXShortcutsSection class];
- }
- return [FLEXObjectExplorerViewController
- exploringObject:object
- customSection:[sectionClass forObject:object]
- ];
- }
- + (void)registerExplorerSection:(Class)explorerClass forClass:(Class)objectClass {
- classesToRegisteredSections[(id<NSCopying>)objectClass] = explorerClass;
- }
- #pragma mark - FLEXGlobalsEntry
- + (NSString *)globalsEntryTitle:(FLEXGlobalsRow)row {
- switch (row) {
- case FLEXGlobalsRowAppDelegate:
- return @"🎟 App Delegate";
- case FLEXGlobalsRowKeyWindow:
- return @"🔑 Key Window";
- case FLEXGlobalsRowRootViewController:
- return @"🌴 Root View Controller";
- case FLEXGlobalsRowProcessInfo:
- return @"🚦 NSProcessInfo.processInfo";
- case FLEXGlobalsRowUserDefaults:
- return @"💾 Preferences";
- case FLEXGlobalsRowMainBundle:
- return @"📦 NSBundle.mainBundle";
- case FLEXGlobalsRowApplication:
- return @"🚀 UIApplication.sharedApplication";
- case FLEXGlobalsRowMainScreen:
- return @"💻 UIScreen.mainScreen";
- case FLEXGlobalsRowCurrentDevice:
- return @"📱 UIDevice.currentDevice";
- case FLEXGlobalsRowPasteboard:
- return @"📋 UIPasteboard.generalPasteboard";
- case FLEXGlobalsRowURLSession:
- return @"📡 NSURLSession.sharedSession";
- case FLEXGlobalsRowURLCache:
- return @"⏳ NSURLCache.sharedURLCache";
- case FLEXGlobalsRowNotificationCenter:
- return @"🔔 NSNotificationCenter.defaultCenter";
- case FLEXGlobalsRowMenuController:
- return @"📎 UIMenuController.sharedMenuController";
- case FLEXGlobalsRowFileManager:
- return @"🗄 NSFileManager.defaultManager";
- case FLEXGlobalsRowTimeZone:
- return @"🌎 NSTimeZone.systemTimeZone";
- case FLEXGlobalsRowLocale:
- return @"🗣 NSLocale.currentLocale";
- case FLEXGlobalsRowCalendar:
- return @"📅 NSCalendar.currentCalendar";
- case FLEXGlobalsRowMainRunLoop:
- return @"🏃🏻♂️ NSRunLoop.mainRunLoop";
- case FLEXGlobalsRowMainThread:
- return @"🧵 NSThread.mainThread";
- case FLEXGlobalsRowOperationQueue:
- return @"📚 NSOperationQueue.mainQueue";
- default: return nil;
- }
- }
- + (UIViewController *)globalsEntryViewController:(FLEXGlobalsRow)row {
- switch (row) {
- case FLEXGlobalsRowAppDelegate: {
- id<UIApplicationDelegate> appDelegate = UIApplication.sharedApplication.delegate;
- return [self explorerViewControllerForObject:appDelegate];
- }
- case FLEXGlobalsRowProcessInfo:
- return [self explorerViewControllerForObject:NSProcessInfo.processInfo];
- case FLEXGlobalsRowUserDefaults:
- return [self explorerViewControllerForObject:NSUserDefaults.standardUserDefaults];
- case FLEXGlobalsRowMainBundle:
- return [self explorerViewControllerForObject:NSBundle.mainBundle];
- case FLEXGlobalsRowApplication:
- return [self explorerViewControllerForObject:UIApplication.sharedApplication];
- case FLEXGlobalsRowMainScreen:
- return [self explorerViewControllerForObject:UIScreen.mainScreen];
- case FLEXGlobalsRowCurrentDevice:
- return [self explorerViewControllerForObject:UIDevice.currentDevice];
- case FLEXGlobalsRowPasteboard:
- #if !TARGET_OS_TV
- return [self explorerViewControllerForObject:UIPasteboard.generalPasteboard];
- #else
- return nil; //FIXME: Probably not a safe fix
- #endif
- case FLEXGlobalsRowURLSession:
- return [self explorerViewControllerForObject:NSURLSession.sharedSession];
- case FLEXGlobalsRowURLCache:
- return [self explorerViewControllerForObject:NSURLCache.sharedURLCache];
- case FLEXGlobalsRowNotificationCenter:
- return [self explorerViewControllerForObject:NSNotificationCenter.defaultCenter];
- case FLEXGlobalsRowMenuController:
- #if !TARGET_OS_TV
- return [self explorerViewControllerForObject:UIMenuController.sharedMenuController];
- #else
- return nil; //FIXME: Probably not a safe fix
- #endif
- case FLEXGlobalsRowFileManager:
- return [self explorerViewControllerForObject:NSFileManager.defaultManager];
- case FLEXGlobalsRowTimeZone:
- return [self explorerViewControllerForObject:NSTimeZone.systemTimeZone];
- case FLEXGlobalsRowLocale:
- return [self explorerViewControllerForObject:NSLocale.currentLocale];
- case FLEXGlobalsRowCalendar:
- return [self explorerViewControllerForObject:NSCalendar.currentCalendar];
- case FLEXGlobalsRowMainRunLoop:
- return [self explorerViewControllerForObject:NSRunLoop.mainRunLoop];
- case FLEXGlobalsRowMainThread:
- return [self explorerViewControllerForObject:NSThread.mainThread];
- case FLEXGlobalsRowOperationQueue:
- return [self explorerViewControllerForObject:NSOperationQueue.mainQueue];
- case FLEXGlobalsRowKeyWindow:
- return [FLEXObjectExplorerFactory
- explorerViewControllerForObject:FLEXUtility.appKeyWindow
- ];
- case FLEXGlobalsRowRootViewController: {
- id<UIApplicationDelegate> delegate = UIApplication.sharedApplication.delegate;
- if ([delegate respondsToSelector:@selector(window)]) {
- return [self explorerViewControllerForObject:delegate.window.rootViewController];
- }
-
- return nil;
- }
- default: return nil;
- }
- }
- + (FLEXGlobalsEntryRowAction)globalsEntryRowAction:(FLEXGlobalsRow)row {
- switch (row) {
- case FLEXGlobalsRowRootViewController: {
- // Check if the app delegate responds to -window. If not, present an alert
- return ^(UITableViewController *host) {
- id<UIApplicationDelegate> delegate = UIApplication.sharedApplication.delegate;
- if ([delegate respondsToSelector:@selector(window)]) {
- UIViewController *explorer = [self explorerViewControllerForObject:
- delegate.window.rootViewController
- ];
- [host.navigationController pushViewController:explorer animated:YES];
- } else {
- NSString *msg = @"The app delegate doesn't respond to -window";
- [FLEXAlert showAlert:@":(" message:msg from:host];
- }
- };
- }
- default: return nil;
- }
- }
- @end
|