Compare commits

...

46 Commits

Author SHA1 Message Date
Tanner Bennett 9db1b544df Use Reflex instead of FLEX in SPM project 2021-11-18 18:45:01 -06:00
Tanner Bennett b58629b8ea Initialize FLEXObjectExplorer.reflexAvailable 2021-11-18 18:45:01 -06:00
Tanner Bennett adeb22af15 Use Reflex and FLEXMirror 2021-11-18 18:45:01 -06:00
Tanner Bennett 6ab183e109 Add FLEXSwiftInternal to check if object from Swift 2021-11-18 18:45:01 -06:00
Tanner Bennett 034f401cb4 Modernize FLEXMirror
Differentiate between class and instance props/methods
2021-11-18 18:45:01 -06:00
Tanner Bennett da1958def5 Add (unused) libflex modulemap file
For my own use case, I dynamically link FLEX, so I need to build Reflex using libflex.tbd as well as this modulemap file after copying it into the Headers folder.
2021-11-18 18:45:01 -06:00
Tanner Bennett ffa658c49b Make a bunch of stuff private that should be private 2021-11-18 18:42:04 -06:00
Tanner Bennett 6066de480f FLEXMacros should be public 2021-11-18 18:20:59 -06:00
Tanner Bennett 0fd7dfa002 SPM: clear Headers folder when running script 2021-11-18 17:50:44 -06:00
Tanner Bennett 60403e614d Ignore Classes/Headers in VS Code search 2021-11-18 17:49:03 -06:00
skytoup fa7db997bd Fix realm database viewer crash 2021-11-16 17:34:11 -08:00
Tanner Bennett d15e72c681 Separate example projects for SPM and Cocoapods 2021-11-14 01:01:24 -06:00
Rafael Fernández 4f1ff7784d Add SPM usage in README, close #482 2021-11-14 00:56:24 -06:00
Tanner Bennett 8129a034e3 Clean up Package.swift 2021-11-14 00:56:24 -06:00
Tanner Bennett 838db6954b Add cxx standard setting 2021-11-14 00:56:24 -06:00
Tanner Bennett 5b3d3af99c Update package.swift 2021-11-14 00:56:24 -06:00
Tanner Bennett 2f9f266493 Update import format 2021-11-14 00:56:24 -06:00
Tanner Bennett 9d94979d08 Exclude LICENSE.md 2021-11-14 00:56:24 -06:00
Tanner Bennett 19b83f4404 headerSearchPath 2021-11-14 00:56:24 -06:00
Tanner Bennett 2b13378d98 Remove unsafe flags 😑 2021-11-14 00:56:24 -06:00
Tanner Bennett 4ae9d41104 Add header references 2021-11-14 00:56:24 -06:00
Tanner Bennett 1490170eb4 Add Package.swift, add script to generate headers
Update script
2021-11-14 00:56:24 -06:00
Tanner Bennett cd695ed106 Bump version 2021-11-14 00:53:41 -06:00
Tanner Bennett 69c1719159 Remove redundant/unused methods in arginputfactory 2021-11-14 00:39:44 -06:00
Tanner Bennett 4019518bf5 Fix #564
entry->log_message.format appears to be garbage on iOS 15, and it doesn't look like it is ever really used in practice anyway, as far as I can tell. Thanks @matrush for pointing this out!
2021-11-14 00:39:44 -06:00
Matt Robinson 3fd8e7c77d Fix CLANG_WARN_STRICT_PROTOTYPES/-Wstrict-prototypes issues
This allows `FLEX` to be linked statically to a binary that has `-Wstrict-prototypes` enabled (for example in CocoaPods without `use_frameworks!`.

Changes:
- Apply `void` to all the empty function/block declarations that don't take arguments.
- Apply `SEL`/`UIImage *` to the others that actually take arguments.
- Remove `CLANG_WARN_STRICT_PROTOTYPES = NO` since the default is enabled.
2021-11-14 00:39:44 -06:00
Tanner Bennett 99c3bcb8c5 Remove init exceptions from flex meta classes 2021-11-14 00:39:44 -06:00
Tanner Bennett b587e96e70 Make FLEXMirror protocol 2021-11-14 00:39:43 -06:00
Tanner Bennett ef8f0a303e Add missing nullability to metadata types 2021-11-14 00:36:52 -06:00
Tanner Bennett cfb1e4caab Add NS_SWIFT_NAME to some enums; does not work
Left it commented out. The enums just disappear for some reason?
2021-11-04 19:11:18 -05:00
daniel 2411c331cd Added a dynamic background color to the WebViewControllers response (Depending on being in Light/Dark mode. See this gist for an example: https://gist.githubusercontent.com/dlevi309/e4d48556836b26125e95cbd82d32a9de/raw/d01112d6e0734db11fa74e2fdb0a1330ddcf82a2/dynamicPage.html) 2021-10-27 13:45:33 -05:00
Tanner Bennett fd4b38f46d Fix bug in tab-close logic 2021-10-26 14:43:20 -05:00
Chaoshuai Lu 269e31894c Remove NSParameterAssert check in closeTab method 2021-10-25 18:24:50 -07:00
Tanner Bennett 2f2da50aed Fix potential crash in FLEXPointerIsReadable
vm_read allocates heap memory, this was intended to be an allocation-free check. Some apps may run out of memory in this code path.
2021-10-20 15:21:26 -05:00
Tanner Bennett d87779212c Add data property to FIRDocumentSnapshot at runtime 2021-10-17 17:33:23 -05:00
Tanner Bennett 5db6a12c6e project.pbxcproj formatting? 2021-10-17 17:33:02 -05:00
Tanner Bennett 6d0f776102 Add a FLEXHeapEnumerator test
Ensure we can spoof an object that is found by FLEXHeapEnumerator and also later prove it isn't a real object
2021-10-17 17:32:09 -05:00
Tanner Bennett 6c83ddc2c7 Refactor FLEXHeapEnumerator and FLEXObjectRef
Move logic that was in FLEXLiveObjectsController into FLEXHeapEnumerator. Also adjust FLEXObjectRef initializers to reflect the type of reference you want to hold to the object. FLEXObjectRef now supports unsafe_unretained and retained references.
2021-10-17 17:31:12 -05:00
Tanner Bennett b510d24e13 Improve FLEXPointerIsValidObjcObject
Compare allocation size to expected instance size
2021-10-17 17:28:59 -05:00
Tanner Bennett 6cdf2e61dc Fix websocket activity not being cleared 2021-10-14 00:28:49 -05:00
Tanner Bennett 9b0ed83ff5 Remove old commented out code 2021-10-13 23:41:13 -05:00
Tanner Bennett dbe1b93f48 Add network observer flag to our NSUserDefaults category 2021-10-13 18:45:52 -05:00
Tanner Bennett 06444f1576 Clean up some comments 2021-10-11 20:21:37 -05:00
Tanner Bennett 9bbf1d0d48 Refactor FLEXNetworkTransaction
Add FLEXURLTransaction to differentiate between NSURL-API-related transactions and other transactions, such as lower level protocols or Firebase ;)
2021-10-11 20:11:04 -05:00
Tanner Bennett 0562f15cd0 Fix incoming WS messages not showing correct details 2021-10-11 20:09:58 -05:00
Tanner Bennett eb63c91481 Send example WS message 2021-10-11 20:09:40 -05:00
142 changed files with 1750 additions and 432 deletions
+5
View File
@@ -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];
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+11 -19
View File
@@ -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
View File
@@ -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
View File
@@ -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
+18 -4
View File
@@ -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
+47 -11
View File
@@ -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];
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/CALayer+FLEX.h
+1
View File
@@ -0,0 +1 @@
../../Classes/FLEX-Categories.h
+1
View File
@@ -0,0 +1 @@
../../Classes/FLEX-Core.h
+1
View File
@@ -0,0 +1 @@
../../Classes/FLEX-ObjectExploring.h
+1
View File
@@ -0,0 +1 @@
../../Classes/FLEX-Runtime.h
+1
View File
@@ -0,0 +1 @@
../../Classes/FLEX.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/FLEXAlert.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/Reflection/FLEXBlockDescription.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/Reflection/FLEXClassBuilder.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Core/Views/Cells/FLEXCodeFontCell.h
+1
View File
@@ -0,0 +1 @@
../../Classes/ObjectExplorers/Sections/FLEXCollectionContentSection.h
+1
View File
@@ -0,0 +1 @@
../../Classes/ObjectExplorers/Sections/FLEXColorPreviewSection.h
+1
View File
@@ -0,0 +1 @@
../../Classes/ObjectExplorers/Sections/FLEXDefaultsContentSection.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Toolbar/FLEXExplorerToolbar.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Toolbar/FLEXExplorerToolbarItem.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Core/Controllers/FLEXFilteringTableViewController.h
+1
View File
@@ -0,0 +1 @@
../../Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/Reflection/FLEXIvar.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Core/Views/Cells/FLEXKeyValueTableViewCell.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/FLEXMacros.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Manager/FLEXManager+Extensibility.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Manager/FLEXManager+Networking.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Manager/FLEXManager.h
+1
View File
@@ -0,0 +1 @@
../../Classes/ObjectExplorers/Sections/FLEXMetadataSection.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/Reflection/FLEXMirror.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Core/Views/Cells/FLEXMultilineTableViewCell.h
+1
View File
@@ -0,0 +1 @@
../../Classes/ObjectExplorers/Sections/FLEXMutableListSection.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Core/Controllers/FLEXNavigationController.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/FLEXObjcInternal.h
+1
View File
@@ -0,0 +1 @@
../../Classes/ObjectExplorers/FLEXObjectExplorer.h
+1
View File
@@ -0,0 +1 @@
../../Classes/ObjectExplorers/FLEXObjectExplorerFactory.h
+1
View File
@@ -0,0 +1 @@
../../Classes/ObjectExplorers/FLEXObjectExplorerViewController.h
+1
View File
@@ -0,0 +1 @@
../../Classes/ObjectExplorers/Sections/FLEXObjectInfoSection.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/Reflection/FLEXProtocol.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/Reflection/FLEXProtocolBuilder.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/FLEXResources.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/FLEXRuntime+Compare.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/FLEXRuntime+UIKitHelpers.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/FLEXRuntimeConstants.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/FLEXRuntimeSafety.h
+1
View File
@@ -0,0 +1 @@
../../Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.h
+1
View File
@@ -0,0 +1 @@
../../Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Core/FLEXSingleRowSection.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Core/Views/Cells/FLEXSubtitleTableViewCell.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/FLEXSwiftInternal.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Core/Views/FLEXTableView.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Core/Views/Cells/FLEXTableViewCell.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Core/Controllers/FLEXTableViewController.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Core/FLEXTableViewSection.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Runtime/Objc/FLEXTypeEncodingParser.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/NSArray+FLEX.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/NSObject+FLEX_Reflection.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/NSTimer+FLEX.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/NSUserDefaults+FLEX.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/UIBarButtonItem+FLEX.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/UIFont+FLEX.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/UIGestureRecognizer+Blocks.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/UIMenu+FLEX.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/UIPasteboard+FLEX.h
+1
View File
@@ -0,0 +1 @@
../../Classes/Utility/Categories/UITextField+Range.h
+8
View File
@@ -0,0 +1,8 @@
module FLEX {
umbrella header "FLEX.h"
link "flex"
export *
module * { export * }
}
+1 -1
View File
@@ -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;
+3 -3
View File
@@ -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]) {
+36 -22
View File
@@ -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
];
}
];
+1
View File
@@ -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];
+27 -8
View File
@@ -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
+51 -14
View File
@@ -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