Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f8b6c05cb |
@@ -76,11 +76,11 @@ NSString * const kCarouselCellReuseIdentifier = @"kCarouselCellReuseIdentifier";
|
||||
_dynamicTypeObserver = [NSNotificationCenter.defaultCenter
|
||||
addObserverForName:UIContentSizeCategoryDidChangeNotification
|
||||
object:nil queue:nil usingBlock:^(NSNotification *note) {
|
||||
__typeof(self) self = weakSelf;
|
||||
[self.collectionView setNeedsLayout];
|
||||
[self setNeedsUpdateConstraints];
|
||||
|
||||
// Notify observers
|
||||
__typeof(self) self = weakSelf;
|
||||
for (void (^block)(FLEXScopeCarousel *) in self.dynamicTypeHandlers) {
|
||||
block(self);
|
||||
}
|
||||
|
||||
@@ -45,9 +45,6 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
/// Only valid while a toolbar drag pan gesture is in progress.
|
||||
@property (nonatomic) CGRect toolbarFrameBeforeDragging;
|
||||
|
||||
/// Only valid while a selected view pan gesture is in progress.
|
||||
@property (nonatomic) CGFloat selectedViewLastPanX;
|
||||
|
||||
/// Borders of all the visible views in the hierarchy at the selection point.
|
||||
/// The keys are NSValues with the corresponding view (nonretained).
|
||||
@property (nonatomic) NSDictionary<NSValue *, UIView *> *outlineViewsForVisibleViews;
|
||||
@@ -61,9 +58,6 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
/// A colored transparent overlay to indicate that the view is selected.
|
||||
@property (nonatomic) UIView *selectedViewOverlay;
|
||||
|
||||
/// Used to actuate changes in view selection on iOS 10+
|
||||
@property (nonatomic, readonly) UISelectionFeedbackGenerator *selectionFBG API_AVAILABLE(ios(10.0));
|
||||
|
||||
/// self.view.window as a \c FLEXWindow
|
||||
@property (nonatomic, readonly) FLEXWindow *window;
|
||||
|
||||
@@ -124,11 +118,6 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
self.movePanGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMovePan:)];
|
||||
self.movePanGR.enabled = self.currentMode == FLEXExplorerModeMove;
|
||||
[self.view addGestureRecognizer:self.movePanGR];
|
||||
|
||||
// Feedback
|
||||
if (@available(iOS 10.0, *)) {
|
||||
_selectionFBG = [UISelectionFeedbackGenerator new];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
@@ -461,16 +450,16 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
];
|
||||
[toolbar.selectedViewDescriptionContainer addGestureRecognizer:self.detailsTapGR];
|
||||
// Swipe gestures for selecting deeper / higher views at a point
|
||||
UIPanGestureRecognizer *leftSwipe = [[UIPanGestureRecognizer alloc]
|
||||
UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc]
|
||||
initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
|
||||
];
|
||||
// UIPanGestureRecognizer *rightSwipe = [[UIPanGestureRecognizer alloc]
|
||||
// initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
|
||||
// ];
|
||||
// leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
|
||||
// rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
|
||||
UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]
|
||||
initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
|
||||
];
|
||||
leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
|
||||
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
|
||||
[toolbar.selectedViewDescriptionContainer addGestureRecognizer:leftSwipe];
|
||||
// [toolbar.selectedViewDescriptionContainer addGestureRecognizer:rightSwipe];
|
||||
[toolbar.selectedViewDescriptionContainer addGestureRecognizer:rightSwipe];
|
||||
|
||||
// Long press gesture to present tabs manager
|
||||
[toolbar.globalsItem addGestureRecognizer:[[UILongPressGestureRecognizer alloc]
|
||||
@@ -609,54 +598,19 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleChangeViewAtPointGesture:(UIPanGestureRecognizer *)sender {
|
||||
- (void)handleChangeViewAtPointGesture:(UISwipeGestureRecognizer *)sender {
|
||||
NSInteger max = self.viewsAtTapPoint.count - 1;
|
||||
NSInteger currentIdx = [self.viewsAtTapPoint indexOfObject:self.selectedView];
|
||||
CGFloat locationX = [sender locationInView:self.view].x;
|
||||
|
||||
// Track the pan gesture: every N points we move along the X axis,
|
||||
// actuate some haptic feedback and move up or down the hierarchy.
|
||||
// We only store the "last" location when we've met the threshold.
|
||||
// We only change the view and actuate feedback if the view selection
|
||||
// changes; that is, as long as we don't go outside or under the array.
|
||||
switch (sender.state) {
|
||||
case UIGestureRecognizerStateBegan: {
|
||||
self.selectedViewLastPanX = locationX;
|
||||
switch (sender.direction) {
|
||||
case UISwipeGestureRecognizerDirectionLeft:
|
||||
self.selectedView = self.viewsAtTapPoint[MIN(max, currentIdx + 1)];
|
||||
break;
|
||||
}
|
||||
case UIGestureRecognizerStateChanged: {
|
||||
static CGFloat kNextLevelThreshold = 20.f;
|
||||
CGFloat lastX = self.selectedViewLastPanX;
|
||||
NSInteger newSelection = currentIdx;
|
||||
|
||||
// Left, go down the hierarchy
|
||||
if (locationX < lastX && (lastX - locationX) >= kNextLevelThreshold) {
|
||||
// Choose a new view index up to the max index
|
||||
newSelection = MIN(max, currentIdx + 1);
|
||||
self.selectedViewLastPanX = locationX;
|
||||
}
|
||||
// Right, go up the hierarchy
|
||||
else if (lastX < locationX && (locationX - lastX) >= kNextLevelThreshold) {
|
||||
// Choose a new view index down to the min index
|
||||
newSelection = MAX(0, currentIdx - 1);
|
||||
self.selectedViewLastPanX = locationX;
|
||||
}
|
||||
|
||||
if (currentIdx != newSelection) {
|
||||
self.selectedView = self.viewsAtTapPoint[newSelection];
|
||||
[self actuateSelectionChangedFeedback];
|
||||
}
|
||||
|
||||
case UISwipeGestureRecognizerDirectionRight:
|
||||
self.selectedView = self.viewsAtTapPoint[MAX(0, currentIdx - 1)];
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)actuateSelectionChangedFeedback {
|
||||
if (@available(iOS 10.0, *)) {
|
||||
[self.selectionFBG selectionChanged];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,15 +45,6 @@ static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
|
||||
[self reloadTableData];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// This doesn't work unless it's wrapped in this dispatch_async call
|
||||
[self.searchController.searchBar becomeFirstResponder];
|
||||
});
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)allClassNames {
|
||||
return self.instanceCountsForClassNames.allKeys;
|
||||
}
|
||||
|
||||
@@ -360,9 +360,7 @@ typedef NS_ENUM(NSUInteger, FLEXFileBrowserSortAttribute) {
|
||||
|
||||
#if FLEX_AT_LEAST_IOS13_SDK
|
||||
|
||||
- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView
|
||||
contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
point:(CGPoint)point __IOS_AVAILABLE(13.0) {
|
||||
- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point __IOS_AVAILABLE(13.0) {
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
return [UIContextMenuConfiguration configurationWithIdentifier:nil
|
||||
previewProvider:nil
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
|
||||
- (NSString *)password {
|
||||
if (self.passwordData.length) {
|
||||
return [[NSString alloc] initWithData:self.passwordData encoding:NSUTF8StringEncoding];
|
||||
return [NSString stringWithCString:self.passwordData.bytes encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
||||
@@ -30,10 +30,10 @@
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
[self addToolbarItems:@[
|
||||
FLEXBarButtonItemSystem(Add, self, @selector(addPressed)),
|
||||
[FLEXBarButtonItemSystem(Trash, self, @selector(trashPressed:)) flex_withTintColor:UIColor.redColor],
|
||||
]];
|
||||
self.navigationItem.rightBarButtonItems = @[
|
||||
[UIBarButtonItem flex_systemItem:UIBarButtonSystemItemTrash target:self action:@selector(trashPressed:)],
|
||||
[UIBarButtonItem flex_systemItem:UIBarButtonSystemItemAdd target:self action:@selector(addPressed)],
|
||||
];
|
||||
|
||||
[self reloadData];
|
||||
}
|
||||
@@ -43,15 +43,14 @@
|
||||
cellConfiguration:^(__kindof FLEXTableViewCell *cell, NSDictionary *item, NSInteger row) {
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
|
||||
id service = item[kFLEXKeychainWhereKey];
|
||||
if ([service isKindOfClass:[NSString class]]) {
|
||||
cell.textLabel.text = service;
|
||||
cell.detailTextLabel.text = item[kFLEXKeychainAccountKey];
|
||||
id account = item[kFLEXKeychainAccountKey];
|
||||
if ([account isKindOfClass:[NSString class]]) {
|
||||
cell.textLabel.text = account;
|
||||
} else {
|
||||
cell.textLabel.text = [NSString stringWithFormat:
|
||||
@"[%@]\n\n%@",
|
||||
NSStringFromClass([service class]),
|
||||
[service description]
|
||||
NSStringFromClass([account class]),
|
||||
[account description]
|
||||
];
|
||||
}
|
||||
} filterMatcher:^BOOL(NSString *filterText, NSDictionary *item) {
|
||||
@@ -130,18 +129,6 @@
|
||||
make.title(@"Clear Keychain");
|
||||
make.message(@"This will remove all keychain items for this app.\n");
|
||||
make.message(@"This action cannot be undone. Are you sure?");
|
||||
make.button(@"Yes, clear the keychain").destructiveStyle().handler(^(NSArray *strings) {
|
||||
[self confirmClearKeychain];
|
||||
});
|
||||
make.button(@"Cancel").cancelStyle();
|
||||
} showFrom:self source:sender];
|
||||
}
|
||||
|
||||
- (void)confirmClearKeychain {
|
||||
[FLEXAlert makeAlert:^(FLEXAlert *make) {
|
||||
make.title(@"ARE YOU SURE?");
|
||||
make.message(@"This action CANNOT BE UNDONE.\nAre you sure you want to continue?\n");
|
||||
make.message(@"If you're sure, scroll to confirm.");
|
||||
make.button(@"Yes, clear the keychain").destructiveStyle().handler(^(NSArray *strings) {
|
||||
for (id account in self.section.list) {
|
||||
[self deleteItem:account];
|
||||
@@ -149,12 +136,8 @@
|
||||
|
||||
[self reloadData];
|
||||
});
|
||||
make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel");
|
||||
make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel");
|
||||
make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel");
|
||||
make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel");
|
||||
make.button(@"Cancel").cancelStyle();
|
||||
} showFrom:self];
|
||||
} showFrom:self source:sender];
|
||||
}
|
||||
|
||||
- (void)addPressed {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#import "FLEXTableView.h"
|
||||
#import "FLEXObjectExplorerFactory.h"
|
||||
#import "FLEXAlert.h"
|
||||
#import "FLEXRuntimeClient.h"
|
||||
|
||||
@interface FLEXObjcRuntimeViewController () <FLEXKeyPathSearchControllerDelegate>
|
||||
|
||||
@@ -29,20 +28,6 @@
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// Long press on navigation bar to initialize webkit legacy
|
||||
//
|
||||
// We call initializeWebKitLegacy automatically before you search
|
||||
// all bundles just to be safe (since touching some classes before
|
||||
// WebKit is initialized will initialize it on a thread other than
|
||||
// the main thread), but sometimes you can encounter this crash
|
||||
// without searching through all bundles, of course.
|
||||
[self.navigationController.navigationBar addGestureRecognizer:[
|
||||
[UILongPressGestureRecognizer alloc]
|
||||
initWithTarget:[FLEXRuntimeClient class]
|
||||
action:@selector(initializeWebKitLegacy)
|
||||
]
|
||||
];
|
||||
|
||||
// Search bar stuff, must be first because this creates self.searchController
|
||||
self.showsSearchBar = YES;
|
||||
self.showSearchBarInitially = YES;
|
||||
|
||||
@@ -265,30 +265,8 @@ static BOOL my_os_log_shim_enabled(void *addr) {
|
||||
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
|
||||
if (action == @selector(copy:)) {
|
||||
// We usually only want to copy the log message itself, not any metadata associated with it.
|
||||
UIPasteboard.generalPasteboard.string = self.logMessages.filteredList[indexPath.row].messageText ?: @"";
|
||||
UIPasteboard.generalPasteboard.string = self.logMessages.filteredList[indexPath.row].messageText;
|
||||
}
|
||||
}
|
||||
|
||||
#if FLEX_AT_LEAST_IOS13_SDK
|
||||
|
||||
- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView
|
||||
contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
point:(CGPoint)point __IOS_AVAILABLE(13.0) {
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
return [UIContextMenuConfiguration configurationWithIdentifier:nil
|
||||
previewProvider:nil
|
||||
actionProvider:^UIMenu *(NSArray<UIMenuElement *> *suggestedActions) {
|
||||
UIAction *copy = [UIAction actionWithTitle:@"Copy"
|
||||
image:nil
|
||||
identifier:@"Copy"
|
||||
handler:^(__kindof UIAction *action) {
|
||||
// We usually only want to copy the log message itself, not any metadata associated with it.
|
||||
UIPasteboard.generalPasteboard.string = weakSelf.logMessages.filteredList[indexPath.row].messageText ?: @"";
|
||||
}];
|
||||
return [UIMenu menuWithTitle:@"" image:nil identifier:nil options:UIMenuOptionsDisplayInline children:@[copy]];
|
||||
}];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@@ -38,9 +38,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)registerGlobalEntryWithName:(NSString *)entryName
|
||||
viewControllerFutureBlock:(UIViewController * (^)(void))viewControllerFutureBlock;
|
||||
|
||||
/// Removes all registered global entries.
|
||||
- (void)clearGlobalEntries;
|
||||
|
||||
#pragma mark - Simulator Shortcuts
|
||||
|
||||
/// Simulator keyboard shortcuts are enabled by default.
|
||||
|
||||
@@ -58,11 +58,6 @@
|
||||
[self.userGlobalEntries addObject:entry];
|
||||
}
|
||||
|
||||
- (void)clearGlobalEntries
|
||||
{
|
||||
[self.userGlobalEntries removeAllObjects];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Simulator Shortcuts
|
||||
|
||||
@@ -100,60 +95,60 @@
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"f" modifiers:0 action:^{
|
||||
[self toggleExplorer];
|
||||
} description:@"Toggle FLEX toolbar"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"g" modifiers:0 action:^{
|
||||
[self showExplorerIfNeeded];
|
||||
[self.explorerViewController toggleMenuTool];
|
||||
} description:@"Toggle FLEX globals menu"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"v" modifiers:0 action:^{
|
||||
[self showExplorerIfNeeded];
|
||||
[self.explorerViewController toggleViewsTool];
|
||||
} description:@"Toggle view hierarchy menu"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"s" modifiers:0 action:^{
|
||||
[self showExplorerIfNeeded];
|
||||
[self.explorerViewController toggleSelectTool];
|
||||
} description:@"Toggle select tool"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"m" modifiers:0 action:^{
|
||||
[self showExplorerIfNeeded];
|
||||
[self.explorerViewController toggleMoveTool];
|
||||
} description:@"Toggle move tool"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"n" modifiers:0 action:^{
|
||||
[self toggleTopViewControllerOfClass:[FLEXNetworkMITMViewController class]];
|
||||
} description:@"Toggle network history view"];
|
||||
|
||||
|
||||
// 't' is for testing: quickly present an object explorer for debugging
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"t" modifiers:0 action:^{
|
||||
[self showExplorerIfNeeded];
|
||||
|
||||
|
||||
[self.explorerViewController toggleToolWithViewControllerProvider:^UINavigationController *{
|
||||
return [FLEXNavigationController withRootViewController:[FLEXObjectExplorerFactory
|
||||
explorerViewControllerForObject:NSBundle.mainBundle
|
||||
]];
|
||||
} completion:nil];
|
||||
} description:@"Present an object explorer for debugging"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:UIKeyInputDownArrow modifiers:0 action:^{
|
||||
if (self.isHidden || ![self.explorerViewController handleDownArrowKeyPressed]) {
|
||||
[self tryScrollDown];
|
||||
}
|
||||
} description:@"Cycle view selection\n\t\tMove view down\n\t\tScroll down"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:UIKeyInputUpArrow modifiers:0 action:^{
|
||||
if (self.isHidden || ![self.explorerViewController handleUpArrowKeyPressed]) {
|
||||
[self tryScrollUp];
|
||||
}
|
||||
} description:@"Cycle view selection\n\t\tMove view up\n\t\tScroll up"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:UIKeyInputRightArrow modifiers:0 action:^{
|
||||
if (!self.isHidden) {
|
||||
[self.explorerViewController handleRightArrowKeyPressed];
|
||||
}
|
||||
} description:@"Move selected view right"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:UIKeyInputLeftArrow modifiers:0 action:^{
|
||||
if (self.isHidden) {
|
||||
[self tryGoBack];
|
||||
@@ -161,15 +156,15 @@
|
||||
[self.explorerViewController handleLeftArrowKeyPressed];
|
||||
}
|
||||
} description:@"Move selected view left"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"?" modifiers:0 action:^{
|
||||
[self toggleTopViewControllerOfClass:[FLEXKeyboardHelpViewController class]];
|
||||
} description:@"Toggle (this) help menu"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:UIKeyInputEscape modifiers:0 action:^{
|
||||
[[self.topViewController presentingViewController] dismissViewControllerAnimated:YES completion:nil];
|
||||
} description:@"End editing text\n\t\tDismiss top view controller"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"o" modifiers:UIKeyModifierCommand|UIKeyModifierShift action:^{
|
||||
[self toggleTopViewControllerOfClass:[FLEXFileBrowserController class]];
|
||||
} description:@"Toggle file browser menu"];
|
||||
@@ -188,7 +183,7 @@
|
||||
if (@available(iOS 11, *)) {
|
||||
return scrollView.adjustedContentInset;
|
||||
}
|
||||
|
||||
|
||||
return scrollView.contentInset;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
}
|
||||
|
||||
if (request.HTTPBody) {
|
||||
NSString *body = [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
|
||||
[curlCommandString appendFormat:@"-d \'%@\'", body];
|
||||
[curlCommandString appendFormat:@"-d \'%@\'", [NSString stringWithCString:request.HTTPBody.bytes encoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
|
||||
return curlCommandString;
|
||||
|
||||
@@ -426,8 +426,7 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
if (transaction.cachedRequestBody.length > 0) {
|
||||
NSString *contentType = [transaction.request valueForHTTPHeaderField:@"Content-Type"];
|
||||
if ([contentType hasPrefix:@"application/x-www-form-urlencoded"]) {
|
||||
NSData *body = [self postBodyDataForTransaction:transaction];
|
||||
NSString *bodyString = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
|
||||
NSString *bodyString = [NSString stringWithCString:[self postBodyDataForTransaction:transaction].bytes encoding:NSUTF8StringEncoding];
|
||||
postBodySection.rows = [self networkDetailRowsFromQueryItems:[FLEXUtility itemsFromQueryString:bodyString]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,21 +21,13 @@
|
||||
#import "FLEXUtility.h"
|
||||
|
||||
@implementation FLEXObjectExplorerFactory
|
||||
static NSMutableDictionary<id<NSCopying>, Class> *classesToRegisteredSections = nil;
|
||||
static NSMutableDictionary<Class, Class> *classesToRegisteredSections = nil;
|
||||
|
||||
+ (void)initialize {
|
||||
if (self == [FLEXObjectExplorerFactory class]) {
|
||||
// DO NOT USE STRING KEYS HERE
|
||||
// We NEED to use the class as a key, because we CANNOT
|
||||
// differentiate a class's name from the metaclass's name.
|
||||
// These mappings are per-class-object, not per-class-name.
|
||||
//
|
||||
// For example, if we used class names, this would result in
|
||||
// the object explorer trying to render a color preview for
|
||||
// the UIColor class object, which is not a color itself.
|
||||
#define ClassKey(name) (id<NSCopying>)[name class]
|
||||
#define ClassKeyByName(str) (id<NSCopying>)NSClassFromString(@ #str)
|
||||
#define MetaclassKey(meta) (id<NSCopying>)object_getClass([meta class])
|
||||
#define ClassKey(name) (Class<NSCopying>)[name class]
|
||||
#define ClassKeyByName(str) (Class<NSCopying>)NSClassFromString(@ #str)
|
||||
#define MetaclassKey(meta) (Class<NSCopying>)object_getClass([meta class])
|
||||
classesToRegisteredSections = [NSMutableDictionary dictionaryWithDictionary:@{
|
||||
MetaclassKey(NSObject) : [FLEXClassShortcuts class],
|
||||
ClassKey(NSArray) : [FLEXCollectionContentSection class],
|
||||
@@ -75,7 +67,7 @@ static NSMutableDictionary<id<NSCopying>, Class> *classesToRegisteredSections =
|
||||
Class sectionClass = nil;
|
||||
Class cls = object_getClass(object);
|
||||
do {
|
||||
sectionClass = classesToRegisteredSections[(id<NSCopying>)cls];
|
||||
sectionClass = classesToRegisteredSections[(Class<NSCopying>)cls];
|
||||
} while (!sectionClass && (cls = [cls superclass]));
|
||||
|
||||
if (!sectionClass) {
|
||||
@@ -89,7 +81,7 @@ static NSMutableDictionary<id<NSCopying>, Class> *classesToRegisteredSections =
|
||||
}
|
||||
|
||||
+ (void)registerExplorerSection:(Class)explorerClass forClass:(Class)objectClass {
|
||||
classesToRegisteredSections[(id<NSCopying>)objectClass] = explorerClass;
|
||||
classesToRegisteredSections[(Class<NSCopying>)objectClass] = explorerClass;
|
||||
}
|
||||
|
||||
#pragma mark - FLEXGlobalsEntry
|
||||
@@ -184,7 +176,7 @@ static NSMutableDictionary<id<NSCopying>, Class> *classesToRegisteredSections =
|
||||
return [self explorerViewControllerForObject:NSThread.mainThread];
|
||||
case FLEXGlobalsRowOperationQueue:
|
||||
return [self explorerViewControllerForObject:NSOperationQueue.mainQueue];
|
||||
|
||||
|
||||
case FLEXGlobalsRowKeyWindow:
|
||||
return [FLEXObjectExplorerFactory
|
||||
explorerViewControllerForObject:FLEXUtility.appKeyWindow
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
+ (instancetype)forObject:(CALayer *)layer {
|
||||
return [self forObject:layer additionalRows:@[
|
||||
[FLEXActionShortcut title:@"Preview Image" subtitle:nil
|
||||
viewer:^UIViewController *(CALayer *layer) {
|
||||
viewer:^UIViewController *(id layer) {
|
||||
return [FLEXImagePreviewViewController previewForLayer:layer];
|
||||
}
|
||||
accessoryType:^UITableViewCellAccessoryType(CALayer *layer) {
|
||||
return CGRectIsEmpty(layer.bounds) ? UITableViewCellAccessoryNone : UITableViewCellAccessoryDisclosureIndicator;
|
||||
accessoryType:^UITableViewCellAccessoryType(id layer) {
|
||||
return UITableViewCellAccessoryDisclosureIndicator;
|
||||
}
|
||||
]
|
||||
]];
|
||||
|
||||
@@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@optional
|
||||
/// Called when the (i) button is pressed if the accessory type includes it
|
||||
- (UIViewController *)editorWith:(id)object forSection:(FLEXTableViewSection *)section;
|
||||
- (UIViewController *)editorWith:(id)object;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -201,10 +201,10 @@
|
||||
|
||||
- (void (^)(__kindof UIViewController *))didPressInfoButtonAction:(NSInteger)row {
|
||||
id<FLEXShortcut> shortcut = self.shortcuts[row];
|
||||
if ([shortcut respondsToSelector:@selector(editorWith:forSection:)]) {
|
||||
if ([shortcut respondsToSelector:@selector(editorWith:)]) {
|
||||
id object = self.object;
|
||||
return ^(UIViewController *host) {
|
||||
UIViewController *editor = [shortcut editorWith:object forSection:self];
|
||||
UIViewController *editor = [shortcut editorWith:object];
|
||||
[host.navigationController pushViewController:editor animated:YES];
|
||||
};
|
||||
}
|
||||
@@ -255,52 +255,31 @@
|
||||
}
|
||||
@end
|
||||
|
||||
#define NewAndSet(ivar) ({ FLEXShortcutsFactory *r = [self sharedFactory]; r->ivar = YES; r; })
|
||||
#define NewAndSet(ivar) ({ FLEXShortcutsFactory *r = [self new]; r->ivar = YES; r; })
|
||||
#define SetIvar(ivar) ({ self->ivar = YES; self; })
|
||||
#define SetParamBlock(ivar) ^(NSArray *p) { self->ivar = p; return self; }
|
||||
|
||||
@implementation FLEXShortcutsFactory
|
||||
|
||||
typedef NSMutableDictionary<Class, NSMutableArray<id<FLEXRuntimeMetadata>> *> RegistrationBuckets;
|
||||
// Class buckets
|
||||
static RegistrationBuckets *cProperties = nil;
|
||||
static RegistrationBuckets *cIvars = nil;
|
||||
static RegistrationBuckets *cMethods = nil;
|
||||
// Metaclass buckets
|
||||
static RegistrationBuckets *mProperties = nil;
|
||||
static RegistrationBuckets *mMethods = nil;
|
||||
|
||||
@implementation FLEXShortcutsFactory {
|
||||
// Class buckets
|
||||
RegistrationBuckets *cProperties;
|
||||
RegistrationBuckets *cIvars;
|
||||
RegistrationBuckets *cMethods;
|
||||
// Metaclass buckets
|
||||
RegistrationBuckets *mProperties;
|
||||
RegistrationBuckets *mMethods;
|
||||
}
|
||||
+ (void)load {
|
||||
cProperties = [NSMutableDictionary new];
|
||||
cIvars = [NSMutableDictionary new];
|
||||
cMethods = [NSMutableDictionary new];
|
||||
|
||||
+ (instancetype)sharedFactory {
|
||||
static FLEXShortcutsFactory *shared = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
shared = [self new];
|
||||
});
|
||||
|
||||
return shared;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
cProperties = [NSMutableDictionary new];
|
||||
cIvars = [NSMutableDictionary new];
|
||||
cMethods = [NSMutableDictionary new];
|
||||
|
||||
mProperties = [NSMutableDictionary new];
|
||||
mMethods = [NSMutableDictionary new];
|
||||
}
|
||||
|
||||
return self;
|
||||
mProperties = [NSMutableDictionary new];
|
||||
mMethods = [NSMutableDictionary new];
|
||||
}
|
||||
|
||||
+ (NSArray<id<FLEXRuntimeMetadata>> *)shortcutsForObjectOrClass:(id)objectOrClass {
|
||||
return [[self sharedFactory] shortcutsForObjectOrClass:objectOrClass];
|
||||
}
|
||||
|
||||
- (NSArray<id<FLEXRuntimeMetadata>> *)shortcutsForObjectOrClass:(id)objectOrClass {
|
||||
|
||||
NSMutableArray<id<FLEXRuntimeMetadata>> *shortcuts = [NSMutableArray new];
|
||||
BOOL isClass = object_isClass(objectOrClass);
|
||||
// The -class does not give you a metaclass, and we want a metaclass
|
||||
@@ -346,43 +325,28 @@ typedef NSMutableDictionary<Class, NSMutableArray<id<FLEXRuntimeMetadata>> *> Re
|
||||
}
|
||||
|
||||
- (void)_register:(NSArray<id<FLEXRuntimeMetadata>> *)items to:(RegistrationBuckets *)global class:(Class)key {
|
||||
@synchronized (self) {
|
||||
// Get (or initialize) the bucket for this class
|
||||
NSMutableArray *bucket = ({
|
||||
id bucket = global[key];
|
||||
if (!bucket) {
|
||||
bucket = [NSMutableArray new];
|
||||
global[(id)key] = bucket;
|
||||
}
|
||||
bucket;
|
||||
});
|
||||
|
||||
if (self->_append) { [bucket addObjectsFromArray:items]; }
|
||||
if (self->_replace) { [bucket setArray:items]; }
|
||||
if (self->_prepend) {
|
||||
if (bucket.count) {
|
||||
// Set new items as array, add old items behind them
|
||||
id copy = bucket.copy;
|
||||
[bucket setArray:items];
|
||||
[bucket addObjectsFromArray:copy];
|
||||
} else {
|
||||
[bucket addObjectsFromArray:items];
|
||||
}
|
||||
// Get (or initialize) the bucket for this class
|
||||
NSMutableArray *bucket = ({
|
||||
id bucket = global[key];
|
||||
if (!bucket) {
|
||||
bucket = [NSMutableArray new];
|
||||
global[(id)key] = bucket;
|
||||
}
|
||||
|
||||
[self reset];
|
||||
}
|
||||
}
|
||||
bucket;
|
||||
});
|
||||
|
||||
- (void)reset {
|
||||
_append = NO;
|
||||
_prepend = NO;
|
||||
_replace = NO;
|
||||
_notInstance = NO;
|
||||
|
||||
_properties = nil;
|
||||
_ivars = nil;
|
||||
_methods = nil;
|
||||
if (self->_append) { [bucket addObjectsFromArray:items]; }
|
||||
if (self->_replace) { [bucket setArray:items]; }
|
||||
if (self->_prepend) {
|
||||
if (bucket.count) {
|
||||
// Set new items as array, add old items behind them
|
||||
id copy = bucket.copy;
|
||||
[bucket setArray:items];
|
||||
[bucket addObjectsFromArray:copy];
|
||||
} else {
|
||||
[bucket addObjectsFromArray:items];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (FLEXShortcutsFactory *)class {
|
||||
@@ -441,15 +405,9 @@ typedef NSMutableDictionary<Class, NSMutableArray<id<FLEXRuntimeMetadata>> *> Re
|
||||
Class metaclass = isMeta ? cls : object_getClass(cls);
|
||||
Class clsForMetadata = instanceMetadata ? cls : metaclass;
|
||||
|
||||
// The factory is a singleton so we don't need to worry about "leaking" it
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wimplicit-retain-self"
|
||||
|
||||
RegistrationBuckets *propertyBucket = instanceShortcut ? cProperties : mProperties;
|
||||
RegistrationBuckets *methodBucket = instanceShortcut ? cMethods : mMethods;
|
||||
RegistrationBuckets *ivarBucket = instanceShortcut ? cIvars : nil;
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
if (self->_properties) {
|
||||
NSArray *items = [self->_properties flex_mapped:^id(NSString *name, NSUInteger idx) {
|
||||
|
||||
@@ -70,18 +70,15 @@
|
||||
return [FLEXObjectExplorerFactory explorerViewControllerForObject:controller];
|
||||
}
|
||||
accessoryType:^UITableViewCellAccessoryType(id view) {
|
||||
return controller ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
|
||||
return controller ? UITableViewCellAccessoryDisclosureIndicator : 0;
|
||||
}
|
||||
],
|
||||
[FLEXActionShortcut title:@"Preview Image" subtitle:^NSString *(UIView *view) {
|
||||
return !CGRectIsEmpty(view.bounds) ? @"" : @"Unavailable with empty bounds";
|
||||
}
|
||||
viewer:^UIViewController *(UIView *view) {
|
||||
[FLEXActionShortcut title:@"Preview Image" subtitle:nil
|
||||
viewer:^UIViewController *(id view) {
|
||||
return [FLEXImagePreviewViewController previewForView:view];
|
||||
}
|
||||
accessoryType:^UITableViewCellAccessoryType(UIView *view) {
|
||||
// Disable preview if bounds are CGRectZero
|
||||
return !CGRectIsEmpty(view.bounds) ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
|
||||
accessoryType:^UITableViewCellAccessoryType(id view) {
|
||||
return UITableViewCellAccessoryDisclosureIndicator;
|
||||
}
|
||||
]
|
||||
]];
|
||||
|
||||
@@ -95,7 +95,6 @@ NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(Class cls) {
|
||||
unsigned int count = 0;
|
||||
Protocol *__unsafe_unretained *list = class_copyProtocolList(cls, &count);
|
||||
NSArray<Protocol *> *protocols = [NSArray arrayWithObjects:list count:count];
|
||||
free(list);
|
||||
|
||||
return [protocols flex_mapped:^id(Protocol *pro, NSUInteger idx) {
|
||||
return [FLEXProtocol protocol:pro];
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
return item;
|
||||
}
|
||||
|
||||
- (UIBarButtonItem *)flex_withTintColor:(UIColor *)tint {
|
||||
- (UIBarButtonItem *)withTintColor:(UIColor *)tint {
|
||||
self.tintColor = tint;
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -11,21 +11,16 @@
|
||||
@implementation UIPasteboard (FLEX)
|
||||
|
||||
- (void)flex_copy:(id)object {
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ([object isKindOfClass:[NSString class]]) {
|
||||
UIPasteboard.generalPasteboard.string = object;
|
||||
} else if([object isKindOfClass:[NSData class]]) {
|
||||
[UIPasteboard.generalPasteboard setData:object forPasteboardType:@"public.data"];
|
||||
} else if ([object isKindOfClass:[NSNumber class]]) {
|
||||
UIPasteboard.generalPasteboard.string = [object stringValue];
|
||||
} else {
|
||||
// TODO: make this an alert instead of an exception
|
||||
[NSException raise:NSInternalInconsistencyException
|
||||
format:@"Tried to copy unsupported type: %@", [object class]];
|
||||
}
|
||||
|
||||
[NSException raise:NSInternalInconsistencyException
|
||||
format:@"Tried to copy unsupported type: %@", [object class]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#define FLEX_IS_TESTING() (NSClassFromString(@"XCTest") != nil)
|
||||
|
||||
/// Whether we want the majority of constructors to run upon load or not.
|
||||
extern BOOL FLEXConstructorsShouldRun(void);
|
||||
extern BOOL FLEXConstructorsShouldRun();
|
||||
|
||||
/// A macro to return from the current procedure if we don't want to run constructors
|
||||
#define FLEX_EXIT_IF_NO_CTORS() if (!FLEXConstructorsShouldRun()) return;
|
||||
|
||||
@@ -52,8 +52,7 @@
|
||||
|
||||
#pragma mark - Misc Icons
|
||||
|
||||
@property (readonly, class) UIImage *checkerPattern;
|
||||
@property (readonly, class) UIColor *checkerPatternColor;
|
||||
@property (readonly, class) UIImage *hierarchyIndentPattern;
|
||||
@property(readonly, class) UIImage *checkerPattern;
|
||||
@property(readonly, class) UIImage *hierarchyIndentPattern;
|
||||
|
||||
@end
|
||||
|
||||
@@ -8838,10 +8838,6 @@ static const u_int8_t FLEXHierarchyIndentPattern3x[] = {
|
||||
return FLEXImage(FLEXCheckerPattern);
|
||||
}
|
||||
|
||||
+ (UIColor *)checkerPatternColor {
|
||||
return [UIColor colorWithPatternImage:FLEXResources.checkerPattern];
|
||||
}
|
||||
|
||||
+ (UIImage *)hierarchyIndentPattern {
|
||||
return FLEXImageTemplate(FLEXHierarchyIndentPattern);
|
||||
}
|
||||
|
||||
@@ -15,21 +15,17 @@
|
||||
#import <zlib.h>
|
||||
|
||||
BOOL FLEXConstructorsShouldRun() {
|
||||
#if FLEX_DISABLE_CTORS
|
||||
return NO;
|
||||
#else
|
||||
static BOOL _FLEXConstructorsShouldRun_storage = YES;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSString *key = @"FLEX_SKIP_INIT";
|
||||
if (getenv(key.UTF8String) || [NSUserDefaults.standardUserDefaults boolForKey:key]) {
|
||||
_FLEXConstructorsShouldRun_storage = NO;
|
||||
}
|
||||
});
|
||||
|
||||
return _FLEXConstructorsShouldRun_storage;
|
||||
#endif
|
||||
static BOOL _FLEXConstructorsShouldRun_storage = YES;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSString *key = @"FLEX_SKIP_INIT";
|
||||
if (getenv(key.UTF8String) || [NSUserDefaults.standardUserDefaults boolForKey:key]) {
|
||||
_FLEXConstructorsShouldRun_storage = NO;
|
||||
}
|
||||
});
|
||||
|
||||
return _FLEXConstructorsShouldRun_storage;
|
||||
}
|
||||
|
||||
@implementation FLEXUtility
|
||||
@@ -135,7 +131,7 @@ BOOL FLEXConstructorsShouldRun() {
|
||||
|
||||
+ (UIImage *)previewImageForView:(UIView *)view {
|
||||
if (CGRectIsEmpty(view.bounds)) {
|
||||
return [UIImage new];
|
||||
return nil;
|
||||
}
|
||||
|
||||
CGSize viewSize = view.bounds.size;
|
||||
@@ -359,18 +355,14 @@ BOOL FLEXConstructorsShouldRun() {
|
||||
|
||||
id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
|
||||
if ([NSJSONSerialization isValidJSONObject:jsonObject]) {
|
||||
// Thanks RaziPour1993
|
||||
prettyString = [[NSString alloc]
|
||||
initWithData:[NSJSONSerialization
|
||||
dataWithJSONObject:jsonObject options:NSJSONWritingPrettyPrinted error:NULL
|
||||
]
|
||||
encoding:NSUTF8StringEncoding
|
||||
];
|
||||
prettyString = [NSString stringWithCString:[NSJSONSerialization
|
||||
dataWithJSONObject:jsonObject options:NSJSONWritingPrettyPrinted error:NULL
|
||||
].bytes encoding:NSUTF8StringEncoding];
|
||||
// NSJSONSerialization escapes forward slashes.
|
||||
// We want pretty json, so run through and unescape the slashes.
|
||||
prettyString = [prettyString stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"];
|
||||
} else {
|
||||
prettyString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
prettyString = [NSString stringWithCString:data.bytes encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
return prettyString;
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
@property (nonatomic) UIImage *image;
|
||||
@property (nonatomic) UIScrollView *scrollView;
|
||||
@property (nonatomic) UIImageView *imageView;
|
||||
@property (nonatomic) UITapGestureRecognizer *bgColorTapGesture;
|
||||
@property (nonatomic) NSInteger backgroundColorIndex;
|
||||
@property (nonatomic, readonly) NSArray<UIColor *> *backgroundColors;
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
@@ -34,19 +31,19 @@
|
||||
}
|
||||
|
||||
+ (instancetype)forImage:(UIImage *)image {
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [[self alloc] initWithImage:image];
|
||||
}
|
||||
|
||||
- (id)initWithImage:(UIImage *)image {
|
||||
NSParameterAssert(image);
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.title = @"Preview";
|
||||
self.image = image;
|
||||
_backgroundColors = @[FLEXResources.checkerPatternColor, UIColor.whiteColor, UIColor.blackColor];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -56,10 +53,12 @@
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.view.backgroundColor = [UIColor colorWithPatternImage:FLEXResources.checkerPattern];
|
||||
|
||||
self.imageView = [[UIImageView alloc] initWithImage:self.image];
|
||||
self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
|
||||
self.scrollView.delegate = self;
|
||||
self.scrollView.backgroundColor = self.backgroundColors.firstObject;
|
||||
self.scrollView.backgroundColor = self.view.backgroundColor;
|
||||
self.scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self.scrollView addSubview:self.imageView];
|
||||
self.scrollView.contentSize = self.imageView.frame.size;
|
||||
@@ -67,14 +66,7 @@
|
||||
self.scrollView.maximumZoomScale = 2.0;
|
||||
[self.view addSubview:self.scrollView];
|
||||
|
||||
self.bgColorTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(changeBackground)];
|
||||
[self.scrollView addGestureRecognizer:self.bgColorTapGesture];
|
||||
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
|
||||
initWithBarButtonSystemItem:UIBarButtonSystemItemAction
|
||||
target:self
|
||||
action:@selector(actionButtonPressed:)
|
||||
];
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(actionButtonPressed:)];
|
||||
}
|
||||
|
||||
- (void)viewDidLayoutSubviews {
|
||||
@@ -107,12 +99,6 @@
|
||||
self.scrollView.contentInset = UIEdgeInsetsMake(verticalInset, horizontalInset, verticalInset, horizontalInset);
|
||||
}
|
||||
|
||||
- (void)changeBackground {
|
||||
self.backgroundColorIndex++;
|
||||
self.backgroundColorIndex %= self.backgroundColors.count;
|
||||
self.scrollView.backgroundColor = self.backgroundColors[self.backgroundColorIndex];
|
||||
}
|
||||
|
||||
- (void)actionButtonPressed:(id)sender {
|
||||
static BOOL canSaveToCameraRoll = NO, didShowWarning = NO;
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
@@ -21,16 +21,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
UserDefaults.standard.set("foo", forKey: "FLEXamplePrefFoo")
|
||||
|
||||
// To show off the system log viewer, send 10 example log messages at 3 second intervals
|
||||
self.repeatingLogExampleTimer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { [weak self] (_) in
|
||||
if let self = self {
|
||||
NSLog("Example log \(self.exampleLogSent)")
|
||||
|
||||
self.exampleLogSent += 1
|
||||
if self.exampleLogSent > self.exampleLogLimit {
|
||||
self.repeatingLogExampleTimer.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
self.repeatingLogExampleTimer = Timer(
|
||||
timeInterval: 3, target: self,
|
||||
selector: #selector(sendExampleLogMessage),
|
||||
userInfo: nil, repeats: true
|
||||
)
|
||||
|
||||
// To show off the network logger, send several misc network requests
|
||||
MiscNetworkRequests.sendExampleRequests()
|
||||
@@ -61,4 +56,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
let exampleLogLimit = 10
|
||||
var exampleLogSent = 0
|
||||
|
||||
func sendExampleLogMessage() {
|
||||
NSLog("Example log \(self.exampleLogSent)")
|
||||
|
||||
self.exampleLogSent += 1
|
||||
if self.exampleLogSent > self.exampleLogLimit {
|
||||
self.repeatingLogExampleTimer.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "FLEX"
|
||||
spec.version = "4.3.0"
|
||||
spec.version = "4.2"
|
||||
spec.summary = "A set of in-app debugging and exploration tools for iOS"
|
||||
spec.description = <<-DESC
|
||||
- Inspect and modify views in the hierarchy.
|
||||
|
||||
Reference in New Issue
Block a user