Compare commits
46 Commits
4.6.0
...
wip/reflex
| Author | SHA1 | Date | |
|---|---|---|---|
| 9db1b544df | |||
| b58629b8ea | |||
| adeb22af15 | |||
| 6ab183e109 | |||
| 034f401cb4 | |||
| da1958def5 | |||
| ffa658c49b | |||
| 6066de480f | |||
| 0fd7dfa002 | |||
| 60403e614d | |||
| fa7db997bd | |||
| d15e72c681 | |||
| 4f1ff7784d | |||
| 8129a034e3 | |||
| 838db6954b | |||
| 5b3d3af99c | |||
| 2f9f266493 | |||
| 9d94979d08 | |||
| 19b83f4404 | |||
| 2b13378d98 | |||
| 4ae9d41104 | |||
| 1490170eb4 | |||
| cd695ed106 | |||
| 69c1719159 | |||
| 4019518bf5 | |||
| 3fd8e7c77d | |||
| 99c3bcb8c5 | |||
| b587e96e70 | |||
| ef8f0a303e | |||
| cfb1e4caab | |||
| 2411c331cd | |||
| fd4b38f46d | |||
| 269e31894c | |||
| 2f2da50aed | |||
| d87779212c | |||
| 5db6a12c6e | |||
| 6d0f776102 | |||
| 6c83ddc2c7 | |||
| b510d24e13 | |||
| 6cdf2e61dc | |||
| 9b0ed83ff5 | |||
| dbe1b93f48 | |||
| 06444f1576 | |||
| 9bbf1d0d48 | |||
| 0562f15cd0 | |||
| eb63c91481 |
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"search.exclude": {
|
||||
"Classes/Headers": true
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@
|
||||
#pragma mark - Search
|
||||
|
||||
- (void)updateSearchResults:(NSString *)newText {
|
||||
NSArray *(^filter)() = ^NSArray *{
|
||||
NSArray *(^filter)(void) = ^NSArray *{
|
||||
self.filterText = newText;
|
||||
|
||||
// Sections will adjust data based on this property
|
||||
|
||||
@@ -96,7 +96,10 @@
|
||||
- (void)dismissAnimated {
|
||||
// Tabs are only closed if the done button is pressed; this
|
||||
// allows you to leave a tab open by dragging down to dismiss
|
||||
[FLEXTabList.sharedList closeTab:self];
|
||||
if ([self.presentingViewController isKindOfClass:[FLEXExplorerViewController class]]) {
|
||||
[FLEXTabList.sharedList closeTab:self];
|
||||
}
|
||||
|
||||
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
|
||||
@@ -559,7 +559,7 @@ static UITextField *kDummyTextField = nil;
|
||||
[self.debounceTimer invalidate];
|
||||
NSString *text = searchController.searchBar.text;
|
||||
|
||||
void (^updateSearchResults)() = ^{
|
||||
void (^updateSearchResults)(void) = ^{
|
||||
if (self.searchResultsUpdater) {
|
||||
[self.searchResultsUpdater updateSearchResults:text];
|
||||
} else {
|
||||
|
||||
@@ -12,7 +12,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FLEXDefaultEditorViewController : FLEXVariableEditorViewController
|
||||
|
||||
+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)())onCommit;
|
||||
+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)(void))onCommit;
|
||||
|
||||
+ (BOOL)canEditDefaultWithValue:(nullable id)currentValue;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
@implementation FLEXDefaultEditorViewController
|
||||
|
||||
+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)())onCommit {
|
||||
+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)(void))onCommit {
|
||||
FLEXDefaultEditorViewController *editor = [self target:defaults data:key commitHandler:onCommit];
|
||||
editor.title = @"Edit Default";
|
||||
return editor;
|
||||
|
||||
@@ -15,9 +15,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@interface FLEXFieldEditorViewController : FLEXVariableEditorViewController
|
||||
|
||||
/// @return nil if the property is readonly or if the type is unsupported
|
||||
+ (nullable instancetype)target:(id)target property:(FLEXProperty *)property commitHandler:(void(^_Nullable)())onCommit;
|
||||
+ (nullable instancetype)target:(id)target property:(FLEXProperty *)property commitHandler:(void(^_Nullable)(void))onCommit;
|
||||
/// @return nil if the ivar type is unsupported
|
||||
+ (nullable instancetype)target:(id)target ivar:(FLEXIvar *)ivar commitHandler:(void(^_Nullable)())onCommit;
|
||||
+ (nullable instancetype)target:(id)target ivar:(FLEXIvar *)ivar commitHandler:(void(^_Nullable)(void))onCommit;
|
||||
|
||||
/// Subclasses can change the button title via the \c title property
|
||||
@property (nonatomic, readonly) UIBarButtonItem *getterButton;
|
||||
|
||||
@@ -30,19 +30,14 @@
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
+ (instancetype)target:(id)target property:(nonnull FLEXProperty *)property commitHandler:(void(^_Nullable)())onCommit {
|
||||
id value = [property getValue:target];
|
||||
if (![self canEditProperty:property onObject:target currentValue:value]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (instancetype)target:(id)target property:(nonnull FLEXProperty *)property commitHandler:(void(^_Nullable)(void))onCommit {
|
||||
FLEXFieldEditorViewController *editor = [self target:target data:property commitHandler:onCommit];
|
||||
editor.title = [@"Property: " stringByAppendingString:property.name];
|
||||
editor.property = property;
|
||||
return editor;
|
||||
}
|
||||
|
||||
+ (instancetype)target:(id)target ivar:(nonnull FLEXIvar *)ivar commitHandler:(void(^_Nullable)())onCommit {
|
||||
+ (instancetype)target:(id)target ivar:(nonnull FLEXIvar *)ivar commitHandler:(void(^_Nullable)(void))onCommit {
|
||||
FLEXFieldEditorViewController *editor = [self target:target data:ivar commitHandler:onCommit];
|
||||
editor.title = [@"Ivar: " stringByAppendingString:ivar.name];
|
||||
editor.ivar = ivar;
|
||||
@@ -151,14 +146,4 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)canEditProperty:(FLEXProperty *)property onObject:(id)object currentValue:(id)value {
|
||||
const FLEXTypeEncoding *typeEncoding = property.attributes.typeEncoding.UTF8String;
|
||||
BOOL canEditType = [FLEXArgumentInputViewFactory canEditFieldWithTypeEncoding:typeEncoding currentValue:value];
|
||||
return canEditType && [object respondsToSelector:property.likelySetter];
|
||||
}
|
||||
|
||||
+ (BOOL)canEditIvar:(Ivar)ivar currentValue:(id)value {
|
||||
return [FLEXArgumentInputViewFactory canEditFieldWithTypeEncoding:ivar_getTypeEncoding(ivar) currentValue:value];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -21,17 +21,17 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@protected
|
||||
id _target;
|
||||
_Nullable id _data;
|
||||
void (^_Nullable _commitHandler)();
|
||||
void (^_Nullable _commitHandler)(void);
|
||||
}
|
||||
|
||||
/// @param target The target of the operation
|
||||
/// @param data The data associated with the operation
|
||||
/// @param onCommit An action to perform when the data changes
|
||||
+ (instancetype)target:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)())onCommit;
|
||||
+ (instancetype)target:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))onCommit;
|
||||
/// @param target The target of the operation
|
||||
/// @param data The data associated with the operation
|
||||
/// @param onCommit An action to perform when the data changes
|
||||
- (id)initWithTarget:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)())onCommit;
|
||||
- (id)initWithTarget:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))onCommit;
|
||||
|
||||
@property (nonatomic, readonly) id target;
|
||||
|
||||
|
||||
@@ -25,11 +25,11 @@
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
+ (instancetype)target:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)())onCommit {
|
||||
+ (instancetype)target:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))onCommit {
|
||||
return [[self alloc] initWithTarget:target data:data commitHandler:onCommit];
|
||||
}
|
||||
|
||||
- (id)initWithTarget:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)())onCommit {
|
||||
- (id)initWithTarget:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))onCommit {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_target = target;
|
||||
|
||||
@@ -460,17 +460,12 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
initWithTarget:self action:@selector(handleToolbarDetailsTapGesture:)
|
||||
];
|
||||
[toolbar.selectedViewDescriptionContainer addGestureRecognizer:self.detailsTapGR];
|
||||
|
||||
// Swipe gestures for selecting deeper / higher views at a point
|
||||
UIPanGestureRecognizer *leftSwipe = [[UIPanGestureRecognizer alloc]
|
||||
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]
|
||||
initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
|
||||
];
|
||||
// UIPanGestureRecognizer *rightSwipe = [[UIPanGestureRecognizer alloc]
|
||||
// initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
|
||||
// ];
|
||||
// leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
|
||||
// rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
|
||||
[toolbar.selectedViewDescriptionContainer addGestureRecognizer:leftSwipe];
|
||||
// [toolbar.selectedViewDescriptionContainer addGestureRecognizer:rightSwipe];
|
||||
[toolbar.selectedViewDescriptionContainer addGestureRecognizer:panGesture];
|
||||
|
||||
// Long press gesture to present tabs manager
|
||||
[toolbar.globalsItem addGestureRecognizer:[[UILongPressGestureRecognizer alloc]
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)showRevertOrDismissAlert:(void(^)())revertBlock {
|
||||
- (void)showRevertOrDismissAlert:(void(^)(void))revertBlock {
|
||||
[self.tableView deselectRowAtIndexPath:self.tableView.indexPathForSelectedRow animated:YES];
|
||||
[self reloadData];
|
||||
[self.tableView reloadData];
|
||||
|
||||
@@ -80,10 +80,10 @@
|
||||
|
||||
- (void)closeTab:(UINavigationController *)tab {
|
||||
NSParameterAssert(tab);
|
||||
NSParameterAssert([self.openTabs containsObject:tab]);
|
||||
NSInteger idx = [self.openTabs indexOfObject:tab];
|
||||
|
||||
[self closeTabAtIndex:idx];
|
||||
if (idx != NSNotFound) {
|
||||
[self closeTabAtIndex:idx];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)closeTabAtIndex:(NSInteger)idx {
|
||||
|
||||
+11
-11
@@ -8,15 +8,15 @@
|
||||
|
||||
|
||||
|
||||
#import <FLEX/UIBarButtonItem+FLEX.h>
|
||||
#import <FLEX/CALayer+FLEX.h>
|
||||
#import <FLEX/UIFont+FLEX.h>
|
||||
#import <FLEX/UIGestureRecognizer+Blocks.h>
|
||||
#import <FLEX/UIPasteboard+FLEX.h>
|
||||
#import <FLEX/UIMenu+FLEX.h>
|
||||
#import <FLEX/UITextField+Range.h>
|
||||
#import <UIBarButtonItem+FLEX.h>
|
||||
#import <CALayer+FLEX.h>
|
||||
#import <UIFont+FLEX.h>
|
||||
#import <UIGestureRecognizer+Blocks.h>
|
||||
#import <UIPasteboard+FLEX.h>
|
||||
#import <UIMenu+FLEX.h>
|
||||
#import <UITextField+Range.h>
|
||||
|
||||
#import <FLEX/NSObject+FLEX_Reflection.h>
|
||||
#import <FLEX/NSArray+FLEX.h>
|
||||
#import <FLEX/NSUserDefaults+FLEX.h>
|
||||
#import <FLEX/NSTimer+FLEX.h>
|
||||
#import <NSObject+FLEX_Reflection.h>
|
||||
#import <NSArray+FLEX.h>
|
||||
#import <NSUserDefaults+FLEX.h>
|
||||
#import <NSTimer+FLEX.h>
|
||||
|
||||
+11
-12
@@ -6,18 +6,17 @@
|
||||
// Copyright © 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import <FLEX/FLEXFilteringTableViewController.h>
|
||||
#import <FLEX/FLEXNavigationController.h>
|
||||
#import <FLEX/FLEXTableViewController.h>
|
||||
#import <FLEX/FLEXTableView.h>
|
||||
#import <FLEXFilteringTableViewController.h>
|
||||
#import <FLEXNavigationController.h>
|
||||
#import <FLEXTableViewController.h>
|
||||
#import <FLEXTableView.h>
|
||||
|
||||
#import <FLEX/FLEXSingleRowSection.h>
|
||||
#import <FLEX/FLEXTableViewSection.h>
|
||||
#import <FLEXSingleRowSection.h>
|
||||
#import <FLEXTableViewSection.h>
|
||||
|
||||
#import <FLEX/FLEXCodeFontCell.h>
|
||||
#import <FLEX/FLEXSubtitleTableViewCell.h>
|
||||
#import <FLEX/FLEXTableViewCell.h>
|
||||
#import <FLEX/FLEXMultilineTableViewCell.h>
|
||||
#import <FLEX/FLEXKeyValueTableViewCell.h>
|
||||
#import <FLEXCodeFontCell.h>
|
||||
#import <FLEXSubtitleTableViewCell.h>
|
||||
#import <FLEXTableViewCell.h>
|
||||
#import <FLEXMultilineTableViewCell.h>
|
||||
#import <FLEXKeyValueTableViewCell.h>
|
||||
|
||||
#import <FLEX/FLEXScopeCarousel.h>
|
||||
|
||||
@@ -6,25 +6,17 @@
|
||||
// Copyright © 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import <FLEX/FLEXObjectExplorerFactory.h>
|
||||
#import <FLEX/FLEXObjectExplorerViewController.h>
|
||||
#import <FLEXObjectExplorerFactory.h>
|
||||
#import <FLEXObjectExplorerViewController.h>
|
||||
|
||||
#import <FLEX/FLEXObjectExplorer.h>
|
||||
#import <FLEXObjectExplorer.h>
|
||||
|
||||
#import <FLEX/FLEXShortcut.h>
|
||||
#import <FLEX/FLEXShortcutsFactory+Defaults.h>
|
||||
#import <FLEX/FLEXShortcutsSection.h>
|
||||
#import <FLEX/FLEXBlockShortcuts.h>
|
||||
#import <FLEX/FLEXBundleShortcuts.h>
|
||||
#import <FLEX/FLEXClassShortcuts.h>
|
||||
#import <FLEX/FLEXImageShortcuts.h>
|
||||
#import <FLEX/FLEXLayerShortcuts.h>
|
||||
#import <FLEX/FLEXViewControllerShortcuts.h>
|
||||
#import <FLEX/FLEXViewShortcuts.h>
|
||||
#import <FLEXShortcut.h>
|
||||
#import <FLEXShortcutsSection.h>
|
||||
|
||||
#import <FLEX/FLEXCollectionContentSection.h>
|
||||
#import <FLEX/FLEXColorPreviewSection.h>
|
||||
#import <FLEX/FLEXDefaultsContentSection.h>
|
||||
#import <FLEX/FLEXMetadataSection.h>
|
||||
#import <FLEX/FLEXMutableListSection.h>
|
||||
#import <FLEX/FLEXObjectInfoSection.h>
|
||||
#import <FLEXCollectionContentSection.h>
|
||||
#import <FLEXColorPreviewSection.h>
|
||||
#import <FLEXDefaultsContentSection.h>
|
||||
#import <FLEXMetadataSection.h>
|
||||
#import <FLEXMutableListSection.h>
|
||||
#import <FLEXObjectInfoSection.h>
|
||||
|
||||
+16
-15
@@ -6,20 +6,21 @@
|
||||
// Copyright © 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import <FLEX/FLEXObjcInternal.h>
|
||||
#import <FLEX/FLEXRuntimeSafety.h>
|
||||
#import <FLEX/FLEXBlockDescription.h>
|
||||
#import <FLEX/FLEXTypeEncodingParser.h>
|
||||
#import <FLEXObjcInternal.h>
|
||||
#import <FLEXSwiftInternal.h>
|
||||
#import <FLEXRuntimeSafety.h>
|
||||
#import <FLEXBlockDescription.h>
|
||||
#import <FLEXTypeEncodingParser.h>
|
||||
|
||||
#import <FLEX/FLEXMirror.h>
|
||||
#import <FLEX/FLEXProtocol.h>
|
||||
#import <FLEX/FLEXProperty.h>
|
||||
#import <FLEX/FLEXIvar.h>
|
||||
#import <FLEX/FLEXMethodBase.h>
|
||||
#import <FLEX/FLEXMethod.h>
|
||||
#import <FLEX/FLEXPropertyAttributes.h>
|
||||
#import <FLEX/FLEXRuntime+Compare.h>
|
||||
#import <FLEX/FLEXRuntime+UIKitHelpers.h>
|
||||
#import <FLEXMirror.h>
|
||||
#import <FLEXProtocol.h>
|
||||
#import <FLEXProperty.h>
|
||||
#import <FLEXIvar.h>
|
||||
#import <FLEXMethodBase.h>
|
||||
#import <FLEXMethod.h>
|
||||
#import <FLEXPropertyAttributes.h>
|
||||
#import <FLEXRuntime+Compare.h>
|
||||
#import <FLEXRuntime+UIKitHelpers.h>
|
||||
|
||||
#import <FLEX/FLEXProtocolBuilder.h>
|
||||
#import <FLEX/FLEXClassBuilder.h>
|
||||
#import <FLEXProtocolBuilder.h>
|
||||
#import <FLEXClassBuilder.h>
|
||||
|
||||
+13
-12
@@ -7,18 +7,19 @@
|
||||
// Copyright (c) 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import <FLEX/FLEXManager.h>
|
||||
#import <FLEX/FLEXManager+Extensibility.h>
|
||||
#import <FLEX/FLEXManager+Networking.h>
|
||||
#import <FLEXManager.h>
|
||||
#import <FLEXManager+Extensibility.h>
|
||||
#import <FLEXManager+Networking.h>
|
||||
|
||||
#import <FLEX/FLEXExplorerToolbar.h>
|
||||
#import <FLEX/FLEXExplorerToolbarItem.h>
|
||||
#import <FLEX/FLEXGlobalsEntry.h>
|
||||
#import <FLEXExplorerToolbar.h>
|
||||
#import <FLEXExplorerToolbarItem.h>
|
||||
#import <FLEXGlobalsEntry.h>
|
||||
|
||||
#import <FLEX/FLEX-Core.h>
|
||||
#import <FLEX/FLEX-Runtime.h>
|
||||
#import <FLEX/FLEX-Categories.h>
|
||||
#import <FLEX/FLEX-ObjectExploring.h>
|
||||
#import <FLEX-Core.h>
|
||||
#import <FLEX-Runtime.h>
|
||||
#import <FLEX-Categories.h>
|
||||
#import <FLEX-ObjectExploring.h>
|
||||
|
||||
#import <FLEX/FLEXAlert.h>
|
||||
#import <FLEX/FLEXResources.h>
|
||||
#import <FLEXMacros.h>
|
||||
#import <FLEXAlert.h>
|
||||
#import <FLEXResources.h>
|
||||
|
||||
@@ -71,7 +71,10 @@
|
||||
self.tables.selectionHandler = ^(FLEXTableListViewController *host, NSString *tableName) {
|
||||
NSArray *rows = [host.dbm queryAllDataInTable:tableName];
|
||||
NSArray *columns = [host.dbm queryAllColumnsOfTable:tableName];
|
||||
NSArray *rowIDs = [host.dbm queryRowIDsInTable:tableName];
|
||||
NSArray *rowIDs = nil;
|
||||
if ([host.dbm respondsToSelector:@selector(queryRowIDsInTable:)]) {
|
||||
rowIDs = [host.dbm queryRowIDsInTable:tableName];
|
||||
}
|
||||
UIViewController *resultsScreen = [FLEXTableContentViewController
|
||||
columns:columns rows:rows rowIDs:rowIDs tableName:tableName database:host.dbm
|
||||
];
|
||||
|
||||
@@ -226,7 +226,10 @@ static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSString *className = self.filteredClassNames[indexPath.row];
|
||||
UIViewController *instances = [FLEXObjectListViewController instancesOfClassWithName:className];
|
||||
UIViewController *instances = [FLEXObjectListViewController
|
||||
instancesOfClassWithName:className
|
||||
retained:YES
|
||||
];
|
||||
[self.navigationController pushViewController:instances animated:YES];
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
/// This will either return a list of the instances, or take you straight
|
||||
/// to the explorer itself if there is only one instance.
|
||||
+ (UIViewController *)instancesOfClassWithName:(NSString *)className;
|
||||
+ (UIViewController *)instancesOfClassWithName:(NSString *)className retained:(BOOL)retain;
|
||||
+ (instancetype)subclassesOfClassWithName:(NSString *)className;
|
||||
+ (instancetype)objectsWithReferencesToObject:(id)object;
|
||||
+ (instancetype)objectsWithReferencesToObject:(id)object retained:(BOOL)retain;
|
||||
|
||||
@end
|
||||
|
||||
@@ -141,83 +141,36 @@ typedef NS_ENUM(NSUInteger, FLEXObjectReferenceSection) {
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (UIViewController *)instancesOfClassWithName:(NSString *)className {
|
||||
const char *classNameCString = className.UTF8String;
|
||||
NSMutableArray *instances = [NSMutableArray new];
|
||||
[FLEXHeapEnumerator enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id object, __unsafe_unretained Class actualClass) {
|
||||
if (strcmp(classNameCString, class_getName(actualClass)) == 0) {
|
||||
// Note: objects of certain classes crash when retain is called.
|
||||
// It is up to the user to avoid tapping into instance lists for these classes.
|
||||
// Ex. OS_dispatch_queue_specific_queue
|
||||
// In the future, we could provide some kind of warning for classes that are known to be problematic.
|
||||
if (malloc_size((__bridge const void *)(object)) > 0) {
|
||||
[instances addObject:object];
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
NSArray<FLEXObjectRef *> *references = [FLEXObjectRef referencingAll:instances];
|
||||
+ (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
|
||||
explorerViewControllerForObject:references.firstObject.object
|
||||
];
|
||||
}
|
||||
|
||||
FLEXObjectListViewController *controller = [[self alloc] initWithReferences:references];
|
||||
controller.title = [NSString stringWithFormat:@"%@ (%lu)", className, (unsigned long)instances.count];
|
||||
controller.title = [NSString stringWithFormat:@"%@ (%@)", className, @(references.count)];
|
||||
return controller;
|
||||
}
|
||||
|
||||
+ (instancetype)subclassesOfClassWithName:(NSString *)className {
|
||||
NSArray<Class> *classes = FLEXGetAllSubclasses(NSClassFromString(className), NO);
|
||||
NSArray<FLEXObjectRef *> *references = [FLEXObjectRef referencingClasses:classes];
|
||||
NSArray<FLEXObjectRef *> *references = [FLEXHeapEnumerator subclassesOfClassWithName:className];
|
||||
FLEXObjectListViewController *controller = [[self alloc] initWithReferences:references];
|
||||
controller.title = [NSString stringWithFormat:@"Subclasses of %@ (%lu)",
|
||||
className, (unsigned long)classes.count
|
||||
controller.title = [NSString stringWithFormat:@"Subclasses of %@ (%@)",
|
||||
className, @(references.count)
|
||||
];
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
+ (instancetype)objectsWithReferencesToObject:(id)object {
|
||||
static Class SwiftObjectClass = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
SwiftObjectClass = NSClassFromString(@"SwiftObject");
|
||||
if (!SwiftObjectClass) {
|
||||
SwiftObjectClass = NSClassFromString(@"Swift._SwiftObject");
|
||||
}
|
||||
});
|
||||
|
||||
NSMutableArray<FLEXObjectRef *> *instances = [NSMutableArray new];
|
||||
[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];
|
||||
NSString *typeEncoding = @(ivar_getTypeEncoding(ivar) ?: "");
|
||||
|
||||
if (typeEncoding.flex_typeIsObjectOrClass) {
|
||||
ptrdiff_t offset = ivar_getOffset(ivar);
|
||||
uintptr_t *fieldPointer = (__bridge void *)tryObject + offset;
|
||||
|
||||
if (*fieldPointer == (uintptr_t)(__bridge void *)object) {
|
||||
NSString *ivarName = @(ivar_getName(ivar) ?: "???");
|
||||
[instances addObject:[FLEXObjectRef referencing:tryObject ivar:ivarName]];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(ivars);
|
||||
tryClass = class_getSuperclass(tryClass);
|
||||
}
|
||||
}];
|
||||
+ (instancetype)objectsWithReferencesToObject:(id)object retained:(BOOL)retain {
|
||||
NSArray<FLEXObjectRef *> *instances = [FLEXHeapEnumerator
|
||||
objectsWithReferencesToObject:object retained:retain
|
||||
];
|
||||
|
||||
FLEXObjectListViewController *viewController = [[self alloc]
|
||||
initWithReferences:instances
|
||||
|
||||
@@ -10,10 +10,19 @@
|
||||
|
||||
@interface FLEXObjectRef : NSObject
|
||||
|
||||
+ (instancetype)referencing:(id)object;
|
||||
+ (instancetype)referencing:(id)object ivar:(NSString *)ivarName;
|
||||
/// Reference an object without affecting its lifespan or or emitting reference-counting operations.
|
||||
+ (instancetype)unretained:(__unsafe_unretained id)object;
|
||||
+ (instancetype)unretained:(__unsafe_unretained id)object ivar:(NSString *)ivarName;
|
||||
|
||||
+ (NSArray<FLEXObjectRef *> *)referencingAll:(NSArray *)objects;
|
||||
/// Reference an object and control its lifespan.
|
||||
+ (instancetype)retained:(id)object;
|
||||
+ (instancetype)retained:(id)object ivar:(NSString *)ivarName;
|
||||
|
||||
/// Reference an object and conditionally choose to retain it or not.
|
||||
+ (instancetype)referencing:(__unsafe_unretained id)object retained:(BOOL)retain;
|
||||
+ (instancetype)referencing:(__unsafe_unretained id)object ivar:(NSString *)ivarName retained:(BOOL)retain;
|
||||
|
||||
+ (NSArray<FLEXObjectRef *> *)referencingAll:(NSArray *)objects retained:(BOOL)retain;
|
||||
/// Classes do not have a summary, and the reference is just the class name.
|
||||
+ (NSArray<FLEXObjectRef *> *)referencingClasses:(NSArray<Class> *)classes;
|
||||
|
||||
@@ -22,6 +31,11 @@
|
||||
/// For instances, this is the result of -[FLEXRuntimeUtility summaryForObject:]
|
||||
/// For classes, there is no summary.
|
||||
@property (nonatomic, readonly) NSString *summary;
|
||||
@property (nonatomic, readonly) id object;
|
||||
@property (nonatomic, readonly, unsafe_unretained) id object;
|
||||
|
||||
/// Retains the referenced object if it is not already retained
|
||||
- (void)retainObject;
|
||||
/// Releases the referenced object if it is already retained
|
||||
- (void)releaseObject;
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,42 +10,68 @@
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
|
||||
@interface FLEXObjectRef ()
|
||||
@interface FLEXObjectRef () {
|
||||
/// Used to retain the object if desired
|
||||
id _retainer;
|
||||
}
|
||||
@property (nonatomic, readonly) BOOL wantsSummary;
|
||||
@end
|
||||
|
||||
@implementation FLEXObjectRef
|
||||
@synthesize summary = _summary;
|
||||
|
||||
+ (instancetype)referencing:(id)object {
|
||||
return [self referencing:object showSummary:YES];
|
||||
+ (instancetype)unretained:(__unsafe_unretained id)object {
|
||||
return [self referencing:object showSummary:YES retained:NO];
|
||||
}
|
||||
|
||||
+ (instancetype)referencing:(id)object showSummary:(BOOL)showSummary {
|
||||
return [[self alloc] initWithObject:object ivarName:nil showSummary:showSummary];
|
||||
+ (instancetype)unretained:(__unsafe_unretained id)object ivar:(NSString *)ivarName {
|
||||
return [[self alloc] initWithObject:object ivarName:ivarName showSummary:YES retained:NO];
|
||||
}
|
||||
|
||||
+ (instancetype)referencing:(id)object ivar:(NSString *)ivarName {
|
||||
return [[self alloc] initWithObject:object ivarName:ivarName showSummary:YES];
|
||||
+ (instancetype)retained:(id)object {
|
||||
return [self referencing:object showSummary:YES retained:YES];
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXObjectRef *> *)referencingAll:(NSArray *)objects {
|
||||
+ (instancetype)retained:(id)object ivar:(NSString *)ivarName {
|
||||
return [[self alloc] initWithObject:object ivarName:ivarName showSummary:YES retained:YES];
|
||||
}
|
||||
|
||||
+ (instancetype)referencing:(__unsafe_unretained id)object retained:(BOOL)retain {
|
||||
return retain ? [self retained:object] : [self unretained:object];
|
||||
}
|
||||
|
||||
+ (instancetype)referencing:(__unsafe_unretained id)object ivar:(NSString *)ivarName retained:(BOOL)retain {
|
||||
return retain ? [self retained:object ivar:ivarName] : [self unretained:object ivar:ivarName];
|
||||
}
|
||||
|
||||
+ (instancetype)referencing:(__unsafe_unretained id)object showSummary:(BOOL)showSummary retained:(BOOL)retain {
|
||||
return [[self alloc] initWithObject:object ivarName:nil showSummary:showSummary retained:retain];
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXObjectRef *> *)referencingAll:(NSArray *)objects retained:(BOOL)retain {
|
||||
return [objects flex_mapped:^id(id obj, NSUInteger idx) {
|
||||
return [self referencing:obj showSummary:YES];
|
||||
return [self referencing:obj showSummary:YES retained:retain];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXObjectRef *> *)referencingClasses:(NSArray<Class> *)classes {
|
||||
return [classes flex_mapped:^id(id obj, NSUInteger idx) {
|
||||
return [self referencing:obj showSummary:NO];
|
||||
return [self referencing:obj showSummary:NO retained:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
- (id)initWithObject:(id)object ivarName:(NSString *)ivar showSummary:(BOOL)showSummary {
|
||||
- (id)initWithObject:(__unsafe_unretained id)object
|
||||
ivarName:(NSString *)ivar
|
||||
showSummary:(BOOL)showSummary
|
||||
retained:(BOOL)retain {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_object = object;
|
||||
_wantsSummary = showSummary;
|
||||
|
||||
if (retain) {
|
||||
_retainer = object;
|
||||
}
|
||||
|
||||
NSString *class = [FLEXRuntimeUtility safeClassNameForObject:object];
|
||||
if (ivar) {
|
||||
@@ -73,4 +99,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)retainObject {
|
||||
if (!_retainer) {
|
||||
_retainer = _object;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)releaseObject {
|
||||
_retainer = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
self = [self initWithNibName:nil bundle:nil];
|
||||
if (self) {
|
||||
self.originalText = text;
|
||||
NSString *htmlString = [NSString stringWithFormat:@"<head><meta name='viewport' content='initial-scale=1.0'></head><body><pre>%@</pre></body>", [FLEXUtility stringByEscapingHTMLEntitiesInString:text]];
|
||||
NSString *htmlString = [NSString stringWithFormat:@"<head><style>:root{ color-scheme: light dark; }</style><meta name='viewport' content='initial-scale=1.0'></head><body><pre>%@</pre></body>", [FLEXUtility stringByEscapingHTMLEntitiesInString:text]];
|
||||
[self.webView loadHTMLString:htmlString baseURL:nil];
|
||||
}
|
||||
return self;
|
||||
|
||||
@@ -195,7 +195,7 @@ static inline NSString * TBWildcardMap(NSString *token, NSString *candidate, TBW
|
||||
"/System/Library/PrivateFrameworks/WebKitLegacy.framework/WebKitLegacy",
|
||||
RTLD_LAZY
|
||||
);
|
||||
void (*WebKitInitialize)() = dlsym(handle, "WebKitInitialize");
|
||||
void (*WebKitInitialize)(void) = dlsym(handle, "WebKitInitialize");
|
||||
if (WebKitInitialize) {
|
||||
NSAssert(NSThread.isMainThread,
|
||||
@"WebKitInitialize can only be called on the main thread"
|
||||
|
||||
@@ -168,11 +168,10 @@ static uint8_t (*OSLogGetType)(void *);
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSince1970:log_message->tv_gmt.tv_sec];
|
||||
|
||||
// Get log message text
|
||||
const char *messageText = OSLogCopyFormattedMessage(log_message);
|
||||
// https://github.com/limneos/oslog/issues/1
|
||||
if (entry->log_message.format && !(strcmp(entry->log_message.format, messageText))) {
|
||||
messageText = (char *)entry->log_message.format;
|
||||
}
|
||||
// https://github.com/FLEXTool/FLEX/issues/564
|
||||
const char *messageText = OSLogCopyFormattedMessage(log_message) ?: "";
|
||||
|
||||
// move messageText from stack to heap
|
||||
NSString *msg = [NSString stringWithUTF8String:messageText];
|
||||
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/CALayer+FLEX.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/FLEX-Categories.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/FLEX-Core.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/FLEX-ObjectExploring.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/FLEX-Runtime.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/FLEX.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/FLEXAlert.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/Reflection/FLEXBlockDescription.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/Reflection/FLEXClassBuilder.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Core/Views/Cells/FLEXCodeFontCell.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/ObjectExplorers/Sections/FLEXCollectionContentSection.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/ObjectExplorers/Sections/FLEXColorPreviewSection.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/ObjectExplorers/Sections/FLEXDefaultsContentSection.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Toolbar/FLEXExplorerToolbar.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Toolbar/FLEXExplorerToolbarItem.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Core/Controllers/FLEXFilteringTableViewController.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/Reflection/FLEXIvar.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Core/Views/Cells/FLEXKeyValueTableViewCell.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/FLEXMacros.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Manager/FLEXManager+Extensibility.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Manager/FLEXManager+Networking.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Manager/FLEXManager.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/ObjectExplorers/Sections/FLEXMetadataSection.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/Reflection/FLEXMirror.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Core/Views/Cells/FLEXMultilineTableViewCell.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/ObjectExplorers/Sections/FLEXMutableListSection.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Core/Controllers/FLEXNavigationController.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/FLEXObjcInternal.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/ObjectExplorers/FLEXObjectExplorer.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/ObjectExplorers/FLEXObjectExplorerFactory.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/ObjectExplorers/FLEXObjectExplorerViewController.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/ObjectExplorers/Sections/FLEXObjectInfoSection.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/Reflection/FLEXProtocol.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/Reflection/FLEXProtocolBuilder.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/FLEXResources.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/FLEXRuntime+Compare.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/FLEXRuntime+UIKitHelpers.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/FLEXRuntimeConstants.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/FLEXRuntimeSafety.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Core/FLEXSingleRowSection.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Core/Views/Cells/FLEXSubtitleTableViewCell.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/FLEXSwiftInternal.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Core/Views/FLEXTableView.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Core/Views/Cells/FLEXTableViewCell.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Core/Controllers/FLEXTableViewController.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Core/FLEXTableViewSection.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Runtime/Objc/FLEXTypeEncodingParser.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/NSArray+FLEX.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/NSObject+FLEX_Reflection.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/NSTimer+FLEX.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/NSUserDefaults+FLEX.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/UIBarButtonItem+FLEX.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/UIFont+FLEX.h
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/UIGestureRecognizer+Blocks.h
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/UIMenu+FLEX.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/UIPasteboard+FLEX.h
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../Classes/Utility/Categories/UITextField+Range.h
|
||||
@@ -0,0 +1,8 @@
|
||||
module FLEX {
|
||||
umbrella header "FLEX.h"
|
||||
|
||||
link "flex"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FLEXMITMDataSource<__covariant TransactionType> : NSObject
|
||||
|
||||
+ (instancetype)dataSourceWithProvider:(NSArray<TransactionType> *(^)())future;
|
||||
+ (instancetype)dataSourceWithProvider:(NSArray<TransactionType> *(^)(void))future;
|
||||
|
||||
@property (nonatomic, readonly) NSArray<TransactionType> *transactions;
|
||||
@property (nonatomic, readonly) NSArray<TransactionType> *allTransactions;
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
#import "FLEXUtility.h"
|
||||
|
||||
@interface FLEXMITMDataSource ()
|
||||
@property (nonatomic, readonly) NSArray *(^dataProvider)();
|
||||
@property (nonatomic, readonly) NSArray *(^dataProvider)(void);
|
||||
@property (nonatomic) NSString *filterString;
|
||||
@end
|
||||
|
||||
@implementation FLEXMITMDataSource
|
||||
|
||||
+ (instancetype)dataSourceWithProvider:(NSArray<id> *(^)())future {
|
||||
+ (instancetype)dataSourceWithProvider:(NSArray<id> *(^)(void))future {
|
||||
FLEXMITMDataSource *ds = [self new];
|
||||
ds->_dataProvider = future;
|
||||
[ds reloadData:nil];
|
||||
@@ -51,7 +51,7 @@
|
||||
} else {
|
||||
[self onBackgroundQueue:^NSArray *{
|
||||
return [self.allTransactions flex_filtered:^BOOL(FLEXNetworkTransaction *entry, NSUInteger idx) {
|
||||
return [entry.request.URL.absoluteString localizedCaseInsensitiveContainsString:searchString];
|
||||
return [entry matchesQuery:searchString];
|
||||
}];
|
||||
} thenOnMainQueue:^(NSArray *filteredNetworkTransactions) {
|
||||
if ([self.filterString isEqual:searchString]) {
|
||||
|
||||
@@ -32,6 +32,8 @@ typedef NS_ENUM(NSUInteger, FLEXNetworkObserverMode) {
|
||||
@property (nonatomic) BOOL updateInProgress;
|
||||
@property (nonatomic) BOOL pendingReload;
|
||||
|
||||
@property (nonatomic, readonly) FLEXNetworkObserverMode mode;
|
||||
|
||||
@property (nonatomic, readonly) FLEXMITMDataSource<FLEXNetworkTransaction *> *dataSource;
|
||||
@property (nonatomic, readonly) FLEXMITMDataSource<FLEXHTTPTransaction *> *HTTPDataSource;
|
||||
@property (nonatomic, readonly) FLEXMITMDataSource<FLEXWebsocketTransaction *> *websocketDataSource;
|
||||
@@ -157,8 +159,12 @@ typedef NS_ENUM(NSUInteger, FLEXNetworkObserverMode) {
|
||||
|
||||
#pragma mark Transactions
|
||||
|
||||
- (FLEXNetworkObserverMode)mode {
|
||||
return self.searchController.searchBar.selectedScopeButtonIndex;
|
||||
}
|
||||
|
||||
- (FLEXMITMDataSource<FLEXNetworkTransaction *> *)dataSource {
|
||||
switch (self.searchController.searchBar.selectedScopeButtonIndex) {
|
||||
switch (self.mode) {
|
||||
case FLEXNetworkObserverModeREST:
|
||||
return self.HTTPDataSource;
|
||||
case FLEXNetworkObserverModeWebsockets:
|
||||
@@ -169,7 +175,7 @@ typedef NS_ENUM(NSUInteger, FLEXNetworkObserverMode) {
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateTransactions:(void(^)())callback {
|
||||
- (void)updateTransactions:(void(^)(void))callback {
|
||||
id completion = ^(FLEXMITMDataSource *dataSource) {
|
||||
// Update byte count
|
||||
[self updateFirstSectionHeader];
|
||||
@@ -274,13 +280,13 @@ typedef NS_ENUM(NSUInteger, FLEXNetworkObserverMode) {
|
||||
|
||||
// Get state before update
|
||||
NSString *currentFilter = self.searchText;
|
||||
FLEXNetworkObserverMode currentMode = self.searchController.searchBar.selectedScopeButtonIndex;
|
||||
FLEXNetworkObserverMode currentMode = self.mode;
|
||||
NSInteger existingRowCount = self.dataSource.transactions.count;
|
||||
|
||||
[self updateTransactions:^{
|
||||
// Compare to state after update
|
||||
NSString *newFilter = self.searchText;
|
||||
FLEXNetworkObserverMode newMode = self.searchController.searchBar.selectedScopeButtonIndex;
|
||||
FLEXNetworkObserverMode newMode = self.mode;
|
||||
NSInteger newRowCount = self.dataSource.transactions.count;
|
||||
NSInteger rowCountDiff = newRowCount - existingRowCount;
|
||||
|
||||
@@ -392,7 +398,7 @@ typedef NS_ENUM(NSUInteger, FLEXNetworkObserverMode) {
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
switch (self.searchController.searchBar.selectedScopeButtonIndex) {
|
||||
switch (self.mode) {
|
||||
case FLEXNetworkObserverModeREST: {
|
||||
FLEXHTTPTransaction *transaction = [self HTTPTransactionAtIndexPath:indexPath];
|
||||
UIViewController *details = [FLEXHTTPTransactionDetailController withTransaction:transaction];
|
||||
@@ -434,13 +440,14 @@ typedef NS_ENUM(NSUInteger, FLEXNetworkObserverMode) {
|
||||
|
||||
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
|
||||
if (action == @selector(copy:)) {
|
||||
NSURLRequest *request = [self transactionAtIndexPath:indexPath].request;
|
||||
UIPasteboard.generalPasteboard.string = request.URL.absoluteString ?: @"";
|
||||
UIPasteboard.generalPasteboard.string = [self transactionAtIndexPath:indexPath].copyString;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point __IOS_AVAILABLE(13.0) {
|
||||
NSURLRequest *request = [self transactionAtIndexPath:indexPath].request;
|
||||
|
||||
FLEXNetworkTransaction *transaction = [self transactionAtIndexPath:indexPath];
|
||||
|
||||
return [UIContextMenuConfiguration
|
||||
configurationWithIdentifier:nil
|
||||
previewProvider:nil
|
||||
@@ -450,25 +457,32 @@ typedef NS_ENUM(NSUInteger, FLEXNetworkObserverMode) {
|
||||
image:nil
|
||||
identifier:nil
|
||||
handler:^(__kindof UIAction *action) {
|
||||
UIPasteboard.generalPasteboard.string = request.URL.absoluteString ?: @"";
|
||||
}
|
||||
];
|
||||
UIAction *denylist = [UIAction
|
||||
actionWithTitle:[NSString stringWithFormat:@"Exclude '%@'", request.URL.host]
|
||||
image:nil
|
||||
identifier:nil
|
||||
handler:^(__kindof UIAction *action) {
|
||||
NSMutableArray *denylist = FLEXNetworkRecorder.defaultRecorder.hostDenylist;
|
||||
[denylist addObject:request.URL.host];
|
||||
[FLEXNetworkRecorder.defaultRecorder clearExcludedTransactions];
|
||||
[FLEXNetworkRecorder.defaultRecorder synchronizeDenylist];
|
||||
[self tryUpdateTransactions];
|
||||
UIPasteboard.generalPasteboard.string = transaction.copyString;
|
||||
}
|
||||
];
|
||||
|
||||
NSArray *children = @[copy];
|
||||
if (self.mode == FLEXNetworkObserverModeREST) {
|
||||
NSURLRequest *request = [self HTTPTransactionAtIndexPath:indexPath].request;
|
||||
UIAction *denylist = [UIAction
|
||||
actionWithTitle:[NSString stringWithFormat:@"Exclude '%@'", request.URL.host]
|
||||
image:nil
|
||||
identifier:nil
|
||||
handler:^(__kindof UIAction *action) {
|
||||
NSMutableArray *denylist = FLEXNetworkRecorder.defaultRecorder.hostDenylist;
|
||||
[denylist addObject:request.URL.host];
|
||||
[FLEXNetworkRecorder.defaultRecorder clearExcludedTransactions];
|
||||
[FLEXNetworkRecorder.defaultRecorder synchronizeDenylist];
|
||||
[self tryUpdateTransactions];
|
||||
}
|
||||
];
|
||||
|
||||
children = [children arrayByAddingObject:denylist];
|
||||
}
|
||||
return [UIMenu
|
||||
menuWithTitle:@"" image:nil identifier:nil
|
||||
options:UIMenuOptionsDisplayInline
|
||||
children:@[copy, denylist]
|
||||
children:children
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
@@ -96,6 +96,7 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
|
||||
- (void)clearRecordedActivity {
|
||||
dispatch_async(self.queue, ^{
|
||||
[self.restCache removeAllObjects];
|
||||
[self.orderedWSTransactions removeAllObjects];
|
||||
[self.orderedHTTPTransactions removeAllObjects];
|
||||
[self.requestIDsToHTTPTransactions removeAllObjects];
|
||||
|
||||
|
||||
@@ -22,36 +22,55 @@ typedef NS_ENUM(NSUInteger, FLEXWebsocketMessageDirection) {
|
||||
FLEXWebsocketOutgoing,
|
||||
};
|
||||
|
||||
/// The shared base class for all types of network transactions.
|
||||
/// Subclasses should implement the descriptions and details properties, and assign a thumbnail.
|
||||
@interface FLEXNetworkTransaction : NSObject
|
||||
|
||||
+ (instancetype)withRequest:(NSURLRequest *)request startTime:(NSDate *)startTime;
|
||||
+ (instancetype)withStartTime:(NSDate *)startTime;
|
||||
|
||||
@property (nonatomic, readonly) NSURLRequest *request;
|
||||
@property (nonatomic, readonly) NSDate *startTime;
|
||||
+ (NSString *)readableStringFromTransactionState:(FLEXNetworkTransactionState)state;
|
||||
|
||||
@property (nonatomic) NSError *error;
|
||||
/// Subclasses can override to provide error state based on response data as well
|
||||
@property (nonatomic, readonly) BOOL displayAsError;
|
||||
@property (nonatomic, readonly) NSDate *startTime;
|
||||
|
||||
@property (nonatomic) FLEXNetworkTransactionState transactionState;
|
||||
@property (nonatomic) int64_t receivedDataLength;
|
||||
/// A small thumbnail to preview the type of/the response
|
||||
@property (nonatomic) UIImage *thumbnail;
|
||||
|
||||
+ (NSString *)readableStringFromTransactionState:(FLEXNetworkTransactionState)state;
|
||||
|
||||
/// Generated by this class using the URL provided by subclasses
|
||||
/// The most prominent line of the cell. Typically a URL endpoint or other distinguishing attribute.
|
||||
/// This line turns red when the transaction indicates an error.
|
||||
@property (nonatomic, readonly) NSString *primaryDescription;
|
||||
/// Something less important, such as a blob of data or the URL's domain.
|
||||
@property (nonatomic, readonly) NSString *secondaryDescription;
|
||||
/// Minor details to display at the bottom of the cell, such as a timestamp, HTTP method, or status.
|
||||
@property (nonatomic, readonly) NSString *tertiaryDescription;
|
||||
|
||||
/// Subclasses should implement for when the transaction is complete
|
||||
@property (nonatomic, readonly) NSArray<NSString *> *details;
|
||||
|
||||
/// The string to copy when the user selects the "copy" action
|
||||
@property (nonatomic, readonly) NSString *copyString;
|
||||
|
||||
/// Whether or not this request should show up when the user searches for a given string
|
||||
- (BOOL)matchesQuery:(NSString *)filterString;
|
||||
|
||||
@end
|
||||
|
||||
/// The shared base class for all NSURL-API-related transactions.
|
||||
/// Descriptions are generated by this class using the URL provided by subclasses.
|
||||
@interface FLEXURLTransaction : FLEXNetworkTransaction
|
||||
|
||||
+ (instancetype)withRequest:(NSURLRequest *)request startTime:(NSDate *)startTime;
|
||||
|
||||
@property (nonatomic, readonly) NSURLRequest *request;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface FLEXHTTPTransaction : FLEXNetworkTransaction
|
||||
@interface FLEXHTTPTransaction : FLEXURLTransaction
|
||||
|
||||
+ (instancetype)request:(NSURLRequest *)request identifier:(NSString *)requestID;
|
||||
|
||||
@@ -68,7 +87,7 @@ typedef NS_ENUM(NSUInteger, FLEXWebsocketMessageDirection) {
|
||||
@end
|
||||
|
||||
|
||||
@interface FLEXWebsocketTransaction : FLEXNetworkTransaction
|
||||
@interface FLEXWebsocketTransaction : FLEXURLTransaction
|
||||
|
||||
+ (instancetype)withMessage:(NSURLSessionWebSocketMessage *)message
|
||||
task:(NSURLSessionWebSocketTask *)task
|
||||
|
||||
@@ -10,14 +10,17 @@
|
||||
#import "FLEXResources.h"
|
||||
#import "FLEXUtility.h"
|
||||
|
||||
@interface FLEXHTTPTransaction ()
|
||||
@property (nonatomic, readwrite) NSData *cachedRequestBody;
|
||||
@interface FLEXNetworkTransaction () {
|
||||
@protected
|
||||
|
||||
NSString *_primaryDescription;
|
||||
NSString *_secondaryDescription;
|
||||
NSString *_tertiaryDescription;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXNetworkTransaction
|
||||
@synthesize primaryDescription = _primaryDescription;
|
||||
@synthesize secondaryDescription = _secondaryDescription;
|
||||
@synthesize tertiaryDescription = _tertiaryDescription;
|
||||
|
||||
+ (NSString *)readableStringFromTransactionState:(FLEXNetworkTransactionState)state {
|
||||
NSString *readableString = nil;
|
||||
@@ -45,13 +48,39 @@
|
||||
return readableString;
|
||||
}
|
||||
|
||||
+ (instancetype)withRequest:(NSURLRequest *)request startTime:(NSDate *)startTime {
|
||||
+ (instancetype)withStartTime:(NSDate *)startTime {
|
||||
FLEXNetworkTransaction *transaction = [self new];
|
||||
transaction->_request = request;
|
||||
transaction->_startTime = startTime;
|
||||
return transaction;
|
||||
}
|
||||
|
||||
- (BOOL)displayAsError {
|
||||
return _error != nil;
|
||||
}
|
||||
|
||||
- (NSString *)copyString {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)matchesQuery:(NSString *)filterString {
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface FLEXURLTransaction ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXURLTransaction
|
||||
|
||||
+ (instancetype)withRequest:(NSURLRequest *)request startTime:(NSDate *)startTime {
|
||||
FLEXURLTransaction *transaction = [self withStartTime:startTime];
|
||||
transaction->_request = request;
|
||||
return transaction;
|
||||
}
|
||||
|
||||
- (NSString *)timestampStringFromRequestDate:(NSDate *)date {
|
||||
static NSDateFormatter *dateFormatter = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
@@ -101,18 +130,18 @@
|
||||
- (NSString *)tertiaryDescription {
|
||||
if (!_tertiaryDescription) {
|
||||
NSMutableArray<NSString *> *detailComponents = [NSMutableArray new];
|
||||
|
||||
|
||||
NSString *timestamp = [self timestampStringFromRequestDate:self.startTime];
|
||||
if (timestamp.length > 0) {
|
||||
[detailComponents addObject:timestamp];
|
||||
}
|
||||
|
||||
|
||||
// Omit method for GET (assumed as default)
|
||||
NSString *httpMethod = self.request.HTTPMethod;
|
||||
if (httpMethod.length > 0) {
|
||||
[detailComponents addObject:httpMethod];
|
||||
}
|
||||
|
||||
|
||||
if (self.transactionState == FLEXNetworkTransactionStateFinished || self.transactionState == FLEXNetworkTransactionStateFailed) {
|
||||
[detailComponents addObjectsFromArray:self.details];
|
||||
} else {
|
||||
@@ -120,7 +149,7 @@
|
||||
NSString *state = [self.class readableStringFromTransactionState:self.transactionState];
|
||||
[detailComponents addObject:state];
|
||||
}
|
||||
|
||||
|
||||
_tertiaryDescription = [detailComponents componentsJoinedByString:@" ・ "];
|
||||
}
|
||||
|
||||
@@ -128,17 +157,24 @@
|
||||
}
|
||||
|
||||
- (void)setTransactionState:(FLEXNetworkTransactionState)transactionState {
|
||||
_transactionState = transactionState;
|
||||
super.transactionState = transactionState;
|
||||
// Reset bottom description
|
||||
_tertiaryDescription = nil;
|
||||
}
|
||||
|
||||
- (BOOL)displayAsError {
|
||||
return _error != nil;
|
||||
- (NSString *)copyString {
|
||||
return self.request.URL.absoluteString;
|
||||
}
|
||||
|
||||
- (BOOL)matchesQuery:(NSString *)filterString {
|
||||
return [self.request.URL.absoluteString localizedCaseInsensitiveContainsString:filterString];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface FLEXHTTPTransaction ()
|
||||
@property (nonatomic, readwrite) NSData *cachedRequestBody;
|
||||
@end
|
||||
|
||||
@implementation FLEXHTTPTransaction
|
||||
|
||||
@@ -225,6 +261,7 @@
|
||||
// Populate receivedDataLength
|
||||
if (direction == FLEXWebsocketIncoming) {
|
||||
wst.receivedDataLength = wst.dataLength;
|
||||
wst.transactionState = FLEXNetworkTransactionStateFinished;
|
||||
}
|
||||
|
||||
// Populate thumbnail image
|
||||
|
||||
@@ -11,10 +11,14 @@
|
||||
// See the LICENSE file distributed with this work for the terms under
|
||||
// which Square, Inc. licenses this file to you.
|
||||
//
|
||||
// Heavily modified and added to by Tanner Bennett and various other contributors.
|
||||
// git blame details these modifications.
|
||||
//
|
||||
|
||||
#import "FLEXNetworkObserver.h"
|
||||
#import "FLEXNetworkRecorder.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "NSUserDefaults+FLEX.h"
|
||||
#import "NSObject+FLEX_Reflection.h"
|
||||
#import "FLEXMethod.h"
|
||||
|
||||
@@ -24,7 +28,6 @@
|
||||
#include <dlfcn.h>
|
||||
|
||||
NSString *const kFLEXNetworkObserverEnabledStateChangedNotification = @"kFLEXNetworkObserverEnabledStateChangedNotification";
|
||||
static NSString *const kFLEXNetworkObserverEnabledDefaultsKey = @"com.flex.FLEXNetworkObserver.enableOnLaunch";
|
||||
|
||||
typedef void (^NSURLSessionAsyncCompletion)(id fileURLOrData, NSURLResponse *response, NSError *error);
|
||||
typedef NSURLSessionTask * (^NSURLSessionNewTaskMethod)(NSURLSession *, id, NSURLSessionAsyncCompletion);
|
||||
@@ -93,7 +96,7 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id<NSUR
|
||||
+ (void)setEnabled:(BOOL)enabled {
|
||||
BOOL previouslyEnabled = [self isEnabled];
|
||||
|
||||
[NSUserDefaults.standardUserDefaults setBool:enabled forKey:kFLEXNetworkObserverEnabledDefaultsKey];
|
||||
NSUserDefaults.standardUserDefaults.flex_networkObserverEnabled = enabled;
|
||||
|
||||
if (enabled) {
|
||||
// Inject if needed. This injection is protected with a dispatch_once, so we're ok calling it multiple times.
|
||||
@@ -107,7 +110,7 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id<NSUR
|
||||
}
|
||||
|
||||
+ (BOOL)isEnabled {
|
||||
return [[NSUserDefaults.standardUserDefaults objectForKey:kFLEXNetworkObserverEnabledDefaultsKey] boolValue];
|
||||
return NSUserDefaults.standardUserDefaults.flex_networkObserverEnabled;
|
||||
}
|
||||
|
||||
+ (void)load {
|
||||
@@ -137,9 +140,11 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id<NSUR
|
||||
#pragma mark Delegate Injection Convenience Methods
|
||||
|
||||
/// All swizzled delegate methods should make use of this guard.
|
||||
/// This will prevent duplicated sniffing when the original implementation calls up to a superclass implementation which we've also swizzled.
|
||||
/// The superclass implementation (and implementations in classes above that) will be executed without interference if called from the original implementation.
|
||||
+ (void)sniffWithoutDuplicationForObject:(NSObject *)object selector:(SEL)selector sniffingBlock:(void (^)(void))sniffingBlock originalImplementationBlock:(void (^)(void))originalImplementationBlock {
|
||||
/// This will prevent duplicated sniffing when the original implementation calls up to a superclass
|
||||
/// implementation which we've also swizzled. The superclass implementation (and implementations in
|
||||
/// classes above that) will be executed without interference if called from the original implementation.
|
||||
+ (void)sniffWithoutDuplicationForObject:(NSObject *)object selector:(SEL)selector
|
||||
sniffingBlock:(void (^)(void))sniffingBlock originalImplementationBlock:(void (^)(void))originalImplementationBlock {
|
||||
// If we don't have an object to detect nested calls on, just run the original implementation and bail.
|
||||
// This case can happen if someone besides the URL loading system calls the delegate methods directly.
|
||||
// See https://github.com/Flipboard/FLEX/issues/61 for an example.
|
||||
|
||||
@@ -71,3 +71,12 @@
|
||||
- (void)reloadClassHierarchy;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface FLEXObjectExplorer (Reflex)
|
||||
|
||||
/// Do not enable this property manually; Reflex will flip the switch when it is loaded.
|
||||
/// If you wish, you may \e disable it manually.
|
||||
@property (nonatomic, class) BOOL reflexAvailable;
|
||||
|
||||
@end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user