Compare commits
143 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ee263a405 | |||
| 02180085a6 | |||
| 5716658571 | |||
| bc39c8894c | |||
| 0dd0fc9418 | |||
| 24d5f3e9b2 | |||
| 693f57eef7 | |||
| 7c17ce0787 | |||
| 400a3ccd1c | |||
| a8cdac1872 | |||
| dedac1f98d | |||
| efa317f0d1 | |||
| 9b55bb10de | |||
| 122fb41fa8 | |||
| d6b5e8c77d | |||
| a6ad98dd53 | |||
| cc35f2086a | |||
| 7038aae6db | |||
| f5433153d0 | |||
| 8b7c59d949 | |||
| faef524b6c | |||
| a2bdc03684 | |||
| bd5f9740b7 | |||
| 505bb2ca41 | |||
| 009711ab3f | |||
| 7ad7653cdf | |||
| e5f51e4dfa | |||
| 92029d2b43 | |||
| 7da059791e | |||
| af57527961 | |||
| 9a8f45663e | |||
| 8528c8a1f6 | |||
| d682fd0ace | |||
| 31af87a81e | |||
| 386d6ae06a | |||
| df79ae7971 | |||
| d30c642707 | |||
| f463e2b43e | |||
| ed49a4fc89 | |||
| b897250fde | |||
| 06709a5afe | |||
| 6eee9e6080 | |||
| c50e6e51c5 | |||
| d1e9248695 | |||
| a535f10d0c | |||
| 009aa5e3f9 | |||
| 675f03fc71 | |||
| 99eccdf4c3 | |||
| 29afa5e80f | |||
| bf26bc6539 | |||
| f7b40646e2 | |||
| 84c1fb159b | |||
| 62ef95ff93 | |||
| 731b729db7 | |||
| a1c464d1a7 | |||
| eb2ecbf9b3 | |||
| 16fab66f7b | |||
| b3e70ac491 | |||
| d5177bb049 | |||
| bb0faeb3cf | |||
| 761feef3c0 | |||
| 352bae03ea | |||
| b0085cae7d | |||
| b2f93f1752 | |||
| 354510f2c4 | |||
| b8c6175193 | |||
| d409b110f5 | |||
| 5c73220158 | |||
| 397721e7ea | |||
| 5714275bcd | |||
| 833c584e41 | |||
| 49b24487c5 | |||
| 6d4eb01a07 | |||
| a752203ff9 | |||
| c69427613d | |||
| 5d75a83568 | |||
| 7642a0632d | |||
| 841054a713 | |||
| 49f368fd63 | |||
| 1dc99250c8 | |||
| 00edccf326 | |||
| 7f3af90645 | |||
| 1a030f06cd | |||
| 0477858bed | |||
| 000e061d00 | |||
| 224978b31b | |||
| 7fd133f13b | |||
| e40054ba1a | |||
| 1761734447 | |||
| f23ee3cd95 | |||
| e455ac0c7d | |||
| 94f68c6dfe | |||
| a22f022014 | |||
| 22e7edb698 | |||
| 52fcda53c5 | |||
| be6c5d0e43 | |||
| 6ed0037f50 | |||
| 81e3a5ff47 | |||
| 2a6e28c9d0 | |||
| 9e928b0b09 | |||
| d5deaad628 | |||
| 232ae8a6fd | |||
| c766e5d94a | |||
| 5f27a2304b | |||
| 0cb0f44f18 | |||
| d1c1aa0a26 | |||
| 832957f621 | |||
| 24985ac984 | |||
| 0b652c2f2a | |||
| 98d83bb438 | |||
| e13717b056 | |||
| 552e687b9c | |||
| fb29421644 | |||
| f5d930bd58 | |||
| 26af4ef476 | |||
| ac8940da26 | |||
| f597152a62 | |||
| 58f94f108c | |||
| a5e0bbd50e | |||
| ac273fbfc9 | |||
| 548fd03bd5 | |||
| b564c25d2a | |||
| bd821dc553 | |||
| e46a33417b | |||
| a3419a841f | |||
| cafc1ba0bd | |||
| 0112c097d9 | |||
| 507d03fd90 | |||
| b6453ac360 | |||
| b693ceb20e | |||
| 31e81a616d | |||
| 928f60b56f | |||
| 12a1900d75 | |||
| c72b6f7e5b | |||
| 3cf9f72dcb | |||
| 9b1318e975 | |||
| d3d0f04c23 | |||
| b606d04944 | |||
| 7afd50d241 | |||
| 94f06d5ff8 | |||
| 85424fd15e | |||
| cff391f78c | |||
| 3e420bb747 |
+6
-2
@@ -1,8 +1,12 @@
|
||||
language: objective-c
|
||||
xcode_workspace: FLEX.xcworkspace
|
||||
xcode_sdk: iphonesimulator
|
||||
before_install:
|
||||
- gem install xcpretty
|
||||
matrix:
|
||||
include:
|
||||
- xcode_scheme: UICatalog
|
||||
xcode_sdk: iphonesimulator
|
||||
- xcode_scheme: FLEX
|
||||
xcode_sdk: iphonesimulator
|
||||
script:
|
||||
- set -o pipefail
|
||||
- xcodebuild -workspace $TRAVIS_XCODE_WORKSPACE -scheme $TRAVIS_XCODE_SCHEME -sdk $TRAVIS_XCODE_SDK build | xcpretty
|
||||
@@ -0,0 +1,3 @@
|
||||
# Contributing to FLEX #
|
||||
|
||||
We welcome contributions! Please open a pull request with your changes.
|
||||
@@ -228,7 +228,7 @@
|
||||
CGFloat hexLabelOriginY = CGRectGetMaxY(self.colorPreviewBox.frame) - self.colorPreviewBox.layer.borderWidth - self.hexLabel.frame.size.height;
|
||||
self.hexLabel.frame = CGRectMake(hexLabelOriginX, hexLabelOriginY, self.hexLabel.frame.size.width, self.hexLabel.frame.size.height);
|
||||
|
||||
NSArray *colorComponentInputViews = @[self.alphaInput, self.redInput, self.greenInput, self.blueInput];
|
||||
NSArray<FLEXColorComponentInputView *> *colorComponentInputViews = @[self.alphaInput, self.redInput, self.greenInput, self.blueInput];
|
||||
for (FLEXColorComponentInputView *inputView in colorComponentInputViews) {
|
||||
CGSize fitSize = [inputView sizeThatFits:constrainSize];
|
||||
inputView.frame = CGRectMake(0, runningOriginY, fitSize.width, fitSize.height);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
@interface FLEXArgumentInputFontsPickerView ()
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *availableFonts;
|
||||
@property (nonatomic, strong) NSMutableArray<NSString *> *availableFonts;
|
||||
|
||||
@end
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
if ([self.availableFonts indexOfObject:inputValue] == NSNotFound) {
|
||||
[self.availableFonts insertObject:inputValue atIndex:0];
|
||||
}
|
||||
[(UIPickerView*)self.inputTextView.inputView selectRow:[self.availableFonts indexOfObject:inputValue] inComponent:0 animated:NO];
|
||||
[(UIPickerView *)self.inputTextView.inputView selectRow:[self.availableFonts indexOfObject:inputValue] inComponent:0 animated:NO];
|
||||
}
|
||||
|
||||
- (id)inputValue
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
- (void)createAvailableFonts
|
||||
{
|
||||
NSMutableArray *unsortedFontsArray = [NSMutableArray array];
|
||||
NSMutableArray<NSString *> *unsortedFontsArray = [NSMutableArray array];
|
||||
for (NSString *eachFontFamily in [UIFont familyNames]) {
|
||||
for (NSString *eachFontName in [UIFont fontNamesForFamilyName:eachFontFamily]) {
|
||||
[unsortedFontsArray addObject:eachFontName];
|
||||
@@ -90,7 +90,7 @@
|
||||
fontLabel = (UILabel*)view;
|
||||
}
|
||||
UIFont *font = [UIFont fontWithName:self.availableFonts[row] size:15.0];
|
||||
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
|
||||
NSDictionary<NSString *, id> *attributesDictionary = [NSDictionary<NSString *, id> dictionaryWithObject:font forKey:NSFontAttributeName];
|
||||
NSAttributedString *attributesString = [[NSAttributedString alloc] initWithString:self.availableFonts[row] attributes:attributesDictionary];
|
||||
fontLabel.attributedText = attributesString;
|
||||
[fontLabel sizeToFit];
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value
|
||||
{
|
||||
static NSArray *primitiveTypes = nil;
|
||||
static NSArray<NSString *> *primitiveTypes = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
primitiveTypes = @[@(@encode(char)),
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
@interface FLEXArgumentInputStructView ()
|
||||
|
||||
@property (nonatomic, strong) NSArray *argumentInputViews;
|
||||
@property (nonatomic, strong) NSArray<FLEXArgumentInputView *> *argumentInputViews;
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
{
|
||||
self = [super initWithArgumentTypeEncoding:typeEncoding];
|
||||
if (self) {
|
||||
NSMutableArray *inputViews = [NSMutableArray array];
|
||||
NSArray *customTitles = [[self class] customFieldTitlesForTypeEncoding:typeEncoding];
|
||||
NSMutableArray<FLEXArgumentInputView *> *inputViews = [NSMutableArray array];
|
||||
NSArray<NSString *> *customTitles = [[self class] customFieldTitlesForTypeEncoding:typeEncoding];
|
||||
[FLEXRuntimeUtility enumerateTypesInStructEncoding:typeEncoding usingBlock:^(NSString *structName, const char *fieldTypeEncoding, NSString *prettyTypeEncoding, NSUInteger fieldIndex, NSUInteger fieldOffset) {
|
||||
|
||||
FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:fieldTypeEncoding];
|
||||
@@ -179,9 +179,9 @@
|
||||
return type && type[0] == '{';
|
||||
}
|
||||
|
||||
+ (NSArray *)customFieldTitlesForTypeEncoding:(const char *)typeEncoding
|
||||
+ (NSArray<NSString *> *)customFieldTitlesForTypeEncoding:(const char *)typeEncoding
|
||||
{
|
||||
NSArray *customTitles = nil;
|
||||
NSArray<NSString *> *customTitles = nil;
|
||||
if (strcmp(typeEncoding, @encode(CGRect)) == 0) {
|
||||
customTitles = @[@"CGPoint origin", @"CGSize size"];
|
||||
} else if (strcmp(typeEncoding, @encode(CGPoint)) == 0) {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
{
|
||||
self = [super initWithFrame:CGRectZero];
|
||||
if (self) {
|
||||
self.typeEncoding = @(typeEncoding);
|
||||
self.typeEncoding = typeEncoding != NULL ? @(typeEncoding) : nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class FLEXArgumentInputView;
|
||||
|
||||
@interface FLEXFieldEditorView : UIView
|
||||
|
||||
@property (nonatomic, copy) NSString *targetDescription;
|
||||
@property (nonatomic, copy) NSString *fieldDescription;
|
||||
|
||||
@property (nonatomic, strong) NSArray *argumentInputViews;
|
||||
@property (nonatomic, strong) NSArray<FLEXArgumentInputView *> *argumentInputViews;
|
||||
|
||||
@end
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setArgumentInputViews:(NSArray *)argumentInputViews
|
||||
- (void)setArgumentInputViews:(NSArray<FLEXArgumentInputView *> *)argumentInputViews
|
||||
{
|
||||
if (![_argumentInputViews isEqual:argumentInputViews]) {
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
@interface FLEXMethodCallingViewController ()
|
||||
|
||||
@property (nonatomic, assign) Method method;
|
||||
@property (nonatomic, assign) FLEXTypeEncoding *returnType;
|
||||
|
||||
@end
|
||||
|
||||
@@ -27,7 +28,8 @@
|
||||
self = [super initWithTarget:target];
|
||||
if (self) {
|
||||
self.method = method;
|
||||
self.title = [self isClassMethod] ? @"Class Method" : @"Method";
|
||||
self.returnType = [FLEXRuntimeUtility returnTypeForMethod:method];
|
||||
self.title = [self isClassMethod] ? @"Class Method" : @"Method";;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -36,10 +38,14 @@
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
self.fieldEditorView.fieldDescription = [FLEXRuntimeUtility prettyNameForMethod:self.method isClassMethod:[self isClassMethod]];
|
||||
NSString *returnType = @((const char *)self.returnType);
|
||||
NSString *methodDescription = [FLEXRuntimeUtility prettyNameForMethod:self.method isClassMethod:[self isClassMethod]];
|
||||
NSString *format = @"Signature:\n%@\n\nReturn Type:\n%@";
|
||||
NSString *info = [NSString stringWithFormat:format, methodDescription, returnType];
|
||||
self.fieldEditorView.fieldDescription = info;
|
||||
|
||||
NSArray *methodComponents = [FLEXRuntimeUtility prettyArgumentComponentsForMethod:self.method];
|
||||
NSMutableArray *argumentInputViews = [NSMutableArray array];
|
||||
NSArray<NSString *> *methodComponents = [FLEXRuntimeUtility prettyArgumentComponentsForMethod:self.method];
|
||||
NSMutableArray<FLEXArgumentInputView *> *argumentInputViews = [NSMutableArray array];
|
||||
unsigned int argumentIndex = kFLEXNumberOfImplicitArgs;
|
||||
for (NSString *methodComponent in methodComponents) {
|
||||
char *argumentTypeEncoding = method_copyArgumentType(self.method, argumentIndex);
|
||||
@@ -54,6 +60,12 @@
|
||||
self.fieldEditorView.argumentInputViews = argumentInputViews;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
free(self.returnType);
|
||||
self.returnType = NULL;
|
||||
}
|
||||
|
||||
- (BOOL)isClassMethod
|
||||
{
|
||||
return self.target && self.target == [self.target class];
|
||||
@@ -88,6 +100,7 @@
|
||||
[alert show];
|
||||
} else if (returnedObject) {
|
||||
// For non-nil (or void) return types, push an explorer view controller to display the returned object
|
||||
returnedObject = [FLEXRuntimeUtility potentiallyUnwrapBoxedPointer:returnedObject type:self.returnType];
|
||||
FLEXObjectExplorerViewController *explorerViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:returnedObject];
|
||||
[self.navigationController pushViewController:explorerViewController animated:YES];
|
||||
} else {
|
||||
|
||||
+6
@@ -17,6 +17,12 @@
|
||||
- (BOOL)shouldReceiveTouchAtWindowPoint:(CGPoint)pointInWindowCoordinates;
|
||||
- (BOOL)wantsWindowToBecomeKey;
|
||||
|
||||
/// @brief Used to present (or dismiss) a modal view controller ("tool"), typically triggered by pressing a button in the toolbar.
|
||||
///
|
||||
/// If a tool is already presented, this method simply dismisses it and calls the completion block.
|
||||
/// If no tool is presented, @code future() @endcode is presented and the completion block is called.
|
||||
- (void)toggleToolWithViewControllerProvider:(UIViewController *(^)(void))future completion:(void(^)(void))completion;
|
||||
|
||||
// Keyboard shortcut helpers
|
||||
|
||||
- (void)toggleSelectTool;
|
||||
+130
-119
@@ -16,6 +16,8 @@
|
||||
#import "FLEXObjectExplorerFactory.h"
|
||||
#import "FLEXNetworkHistoryTableViewController.h"
|
||||
|
||||
static NSString *const kFLEXToolbarTopMarginDefaultsKey = @"com.flex.FLEXToolbar.topMargin";
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
FLEXExplorerModeDefault,
|
||||
FLEXExplorerModeSelect,
|
||||
@@ -43,10 +45,10 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
|
||||
/// Borders of all the visible views in the hierarchy at the selection point.
|
||||
/// The keys are NSValues with the correponding view (nonretained).
|
||||
@property (nonatomic, strong) NSDictionary *outlineViewsForVisibleViews;
|
||||
@property (nonatomic, strong) NSDictionary<NSValue *, UIView *> *outlineViewsForVisibleViews;
|
||||
|
||||
/// The actual views at the selection point with the deepest view last.
|
||||
@property (nonatomic, strong) NSArray *viewsAtTapPoint;
|
||||
@property (nonatomic, strong) NSArray<UIView *> *viewsAtTapPoint;
|
||||
|
||||
/// The view that we're currently highlighting with an overlay and displaying details for.
|
||||
@property (nonatomic, strong) UIView *selectedView;
|
||||
@@ -66,7 +68,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
@property (nonatomic, assign) UIStatusBarStyle previousStatusBarStyle;
|
||||
|
||||
/// All views that we're KVOing. Used to help us clean up properly.
|
||||
@property (nonatomic, strong) NSMutableSet *observedViews;
|
||||
@property (nonatomic, strong) NSMutableSet<UIView *> *observedViews;
|
||||
|
||||
@end
|
||||
|
||||
@@ -94,10 +96,14 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
|
||||
// Toolbar
|
||||
self.explorerToolbar = [[FLEXExplorerToolbar alloc] init];
|
||||
CGSize toolbarSize = [self.explorerToolbar sizeThatFits:self.view.bounds.size];
|
||||
|
||||
// Start the toolbar off below any bars that may be at the top of the view.
|
||||
CGFloat toolbarOriginY = 100.0;
|
||||
self.explorerToolbar.frame = CGRectMake(0.0, toolbarOriginY, toolbarSize.width, toolbarSize.height);
|
||||
id toolbarOriginYDefault = [[NSUserDefaults standardUserDefaults] objectForKey:kFLEXToolbarTopMarginDefaultsKey];
|
||||
CGFloat toolbarOriginY = toolbarOriginYDefault ? [toolbarOriginYDefault doubleValue] : 100;
|
||||
|
||||
CGRect safeArea = [self viewSafeArea];
|
||||
CGSize toolbarSize = [self.explorerToolbar sizeThatFits:CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(safeArea))];
|
||||
[self updateToolbarPositionWithUnconstrainedFrame:CGRectMake(CGRectGetMinX(safeArea), toolbarOriginY, toolbarSize.width, toolbarSize.height)];
|
||||
self.explorerToolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;
|
||||
[self.view addSubview:self.explorerToolbar];
|
||||
[self setupToolbarActions];
|
||||
@@ -165,32 +171,30 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
return shouldAutorotate;
|
||||
}
|
||||
|
||||
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
|
||||
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
|
||||
{
|
||||
for (UIView *outlineView in [self.outlineViewsForVisibleViews allValues]) {
|
||||
outlineView.hidden = YES;
|
||||
}
|
||||
self.selectedViewOverlay.hidden = YES;
|
||||
}
|
||||
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
||||
for (UIView *outlineView in [self.outlineViewsForVisibleViews allValues]) {
|
||||
outlineView.hidden = YES;
|
||||
}
|
||||
self.selectedViewOverlay.hidden = YES;
|
||||
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
||||
for (UIView *view in self.viewsAtTapPoint) {
|
||||
NSValue *key = [NSValue valueWithNonretainedObject:view];
|
||||
UIView *outlineView = self.outlineViewsForVisibleViews[key];
|
||||
outlineView.frame = [self frameInLocalCoordinatesForView:view];
|
||||
if (self.currentMode == FLEXExplorerModeSelect) {
|
||||
outlineView.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
|
||||
{
|
||||
for (UIView *view in self.viewsAtTapPoint) {
|
||||
NSValue *key = [NSValue valueWithNonretainedObject:view];
|
||||
UIView *outlineView = self.outlineViewsForVisibleViews[key];
|
||||
outlineView.frame = [self frameInLocalCoordinatesForView:view];
|
||||
if (self.currentMode == FLEXExplorerModeSelect) {
|
||||
outlineView.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
if (self.selectedView) {
|
||||
self.selectedViewOverlay.frame = [self frameInLocalCoordinatesForView:self.selectedView];
|
||||
self.selectedViewOverlay.hidden = NO;
|
||||
}
|
||||
if (self.selectedView) {
|
||||
self.selectedViewOverlay.frame = [self frameInLocalCoordinatesForView:self.selectedView];
|
||||
self.selectedViewOverlay.hidden = NO;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Setter Overrides
|
||||
|
||||
- (void)setSelectedView:(UIView *)selectedView
|
||||
@@ -206,7 +210,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
|
||||
// Update the toolbar and selected overlay
|
||||
self.explorerToolbar.selectedViewDescription = [FLEXUtility descriptionForView:selectedView includingFrame:YES];
|
||||
self.explorerToolbar.selectedViewOverlayColor = [FLEXUtility consistentRandomColorForObject:selectedView];;
|
||||
self.explorerToolbar.selectedViewOverlayColor = [FLEXUtility consistentRandomColorForObject:selectedView];
|
||||
|
||||
if (selectedView) {
|
||||
if (!self.selectedViewOverlay) {
|
||||
@@ -232,7 +236,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setViewsAtTapPoint:(NSArray *)viewsAtTapPoint
|
||||
- (void)setViewsAtTapPoint:(NSArray<UIView *> *)viewsAtTapPoint
|
||||
{
|
||||
if (![_viewsAtTapPoint isEqual:viewsAtTapPoint]) {
|
||||
for (UIView *view in _viewsAtTapPoint) {
|
||||
@@ -262,7 +266,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
|
||||
case FLEXExplorerModeSelect:
|
||||
// Make sure the outline views are unhidden in case we came from the move mode.
|
||||
for (id key in self.outlineViewsForVisibleViews) {
|
||||
for (NSValue *key in self.outlineViewsForVisibleViews) {
|
||||
UIView *outlineView = self.outlineViewsForVisibleViews[key];
|
||||
outlineView.hidden = NO;
|
||||
}
|
||||
@@ -270,7 +274,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
|
||||
case FLEXExplorerModeMove:
|
||||
// Hide all the outline views to focus on the selected view, which is the only one that will move.
|
||||
for (id key in self.outlineViewsForVisibleViews) {
|
||||
for (NSValue *key in self.outlineViewsForVisibleViews) {
|
||||
UIView *outlineView = self.outlineViewsForVisibleViews[key];
|
||||
outlineView.hidden = YES;
|
||||
}
|
||||
@@ -311,9 +315,9 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
[self.observedViews removeObject:view];
|
||||
}
|
||||
|
||||
+ (NSArray *)viewKeyPathsToTrack
|
||||
+ (NSArray<NSString *> *)viewKeyPathsToTrack
|
||||
{
|
||||
static NSArray *trackedViewKeyPaths = nil;
|
||||
static NSArray<NSString *> *trackedViewKeyPaths = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSString *frameKeyPath = NSStringFromSelector(@selector(frame));
|
||||
@@ -322,7 +326,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
return trackedViewKeyPaths;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context
|
||||
{
|
||||
[self updateOverlayAndDescriptionForObjectIfNeeded:object];
|
||||
}
|
||||
@@ -376,10 +380,10 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
[self toggleViewsTool];
|
||||
}
|
||||
|
||||
- (NSArray *)allViewsInHierarchy
|
||||
- (NSArray<UIView *> *)allViewsInHierarchy
|
||||
{
|
||||
NSMutableArray *allViews = [NSMutableArray array];
|
||||
NSArray *windows = [self allWindows];
|
||||
NSMutableArray<UIView *> *allViews = [NSMutableArray array];
|
||||
NSArray<UIWindow *> *windows = [FLEXUtility allWindows];
|
||||
for (UIWindow *window in windows) {
|
||||
if (window != self.view.window) {
|
||||
[allViews addObject:window];
|
||||
@@ -389,28 +393,6 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
return allViews;
|
||||
}
|
||||
|
||||
- (NSArray *)allWindows
|
||||
{
|
||||
BOOL includeInternalWindows = YES;
|
||||
BOOL onlyVisibleWindows = NO;
|
||||
|
||||
NSArray *allWindowsComponents = @[@"al", @"lWindo", @"wsIncl", @"udingInt", @"ernalWin", @"dows:o", @"nlyVisi", @"bleWin", @"dows:"];
|
||||
SEL allWindowsSelector = NSSelectorFromString([allWindowsComponents componentsJoinedByString:@""]);
|
||||
|
||||
NSMethodSignature *methodSignature = [[UIWindow class] methodSignatureForSelector:allWindowsSelector];
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
|
||||
|
||||
invocation.target = [UIWindow class];
|
||||
invocation.selector = allWindowsSelector;
|
||||
[invocation setArgument:&includeInternalWindows atIndex:2];
|
||||
[invocation setArgument:&onlyVisibleWindows atIndex:3];
|
||||
[invocation invoke];
|
||||
|
||||
__unsafe_unretained NSArray *windows = nil;
|
||||
[invocation getReturnValue:&windows];
|
||||
return windows;
|
||||
}
|
||||
|
||||
- (UIWindow *)statusWindow
|
||||
{
|
||||
NSString *statusBarString = [NSString stringWithFormat:@"%@arWindow", @"_statusB"];
|
||||
@@ -484,14 +466,24 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
CGRect newToolbarFrame = self.toolbarFrameBeforeDragging;
|
||||
newToolbarFrame.origin.y += translation.y;
|
||||
|
||||
CGFloat maxY = CGRectGetMaxY(self.view.bounds) - newToolbarFrame.size.height;
|
||||
if (newToolbarFrame.origin.y < 0.0) {
|
||||
newToolbarFrame.origin.y = 0.0;
|
||||
} else if (newToolbarFrame.origin.y > maxY) {
|
||||
newToolbarFrame.origin.y = maxY;
|
||||
[self updateToolbarPositionWithUnconstrainedFrame:newToolbarFrame];
|
||||
}
|
||||
|
||||
- (void)updateToolbarPositionWithUnconstrainedFrame:(CGRect)unconstrainedFrame
|
||||
{
|
||||
CGRect safeArea = [self viewSafeArea];
|
||||
// We only constrain the Y-axis because We want the toolbar to handle the X-axis safeArea layout by itself
|
||||
CGFloat minY = CGRectGetMinY(safeArea);
|
||||
CGFloat maxY = CGRectGetMaxY(safeArea) - unconstrainedFrame.size.height;
|
||||
if (unconstrainedFrame.origin.y < minY) {
|
||||
unconstrainedFrame.origin.y = minY;
|
||||
} else if (unconstrainedFrame.origin.y > maxY) {
|
||||
unconstrainedFrame.origin.y = maxY;
|
||||
}
|
||||
|
||||
self.explorerToolbar.frame = newToolbarFrame;
|
||||
|
||||
self.explorerToolbar.frame = unconstrainedFrame;
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:unconstrainedFrame.origin.y forKey:kFLEXToolbarTopMarginDefaultsKey];
|
||||
}
|
||||
|
||||
- (void)handleToolbarHintTapGesture:(UITapGestureRecognizer *)tapGR
|
||||
@@ -548,8 +540,8 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
|
||||
// For outlined views and the selected view, only use visible views.
|
||||
// Outlining hidden views adds clutter and makes the selection behavior confusing.
|
||||
NSArray *visibleViewsAtTapPoint = [self viewsAtPoint:selectionPointInWindow skipHiddenViews:YES];
|
||||
NSMutableDictionary *newOutlineViewsForVisibleViews = [NSMutableDictionary dictionary];
|
||||
NSArray<UIView *> *visibleViewsAtTapPoint = [self viewsAtPoint:selectionPointInWindow skipHiddenViews:YES];
|
||||
NSMutableDictionary<NSValue *, UIView *> *newOutlineViewsForVisibleViews = [NSMutableDictionary dictionary];
|
||||
for (UIView *view in visibleViewsAtTapPoint) {
|
||||
UIView *outlineView = [self outlineViewForView:view];
|
||||
[self.view addSubview:outlineView];
|
||||
@@ -577,17 +569,17 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
|
||||
- (void)removeAndClearOutlineViews
|
||||
{
|
||||
for (id key in self.outlineViewsForVisibleViews) {
|
||||
for (NSValue *key in self.outlineViewsForVisibleViews) {
|
||||
UIView *outlineView = self.outlineViewsForVisibleViews[key];
|
||||
[outlineView removeFromSuperview];
|
||||
}
|
||||
self.outlineViewsForVisibleViews = nil;
|
||||
}
|
||||
|
||||
- (NSArray *)viewsAtPoint:(CGPoint)tapPointInWindow skipHiddenViews:(BOOL)skipHidden
|
||||
- (NSArray<UIView *> *)viewsAtPoint:(CGPoint)tapPointInWindow skipHiddenViews:(BOOL)skipHidden
|
||||
{
|
||||
NSMutableArray *views = [NSMutableArray array];
|
||||
for (UIWindow *window in [self allWindows]) {
|
||||
NSMutableArray<UIView *> *views = [NSMutableArray array];
|
||||
for (UIWindow *window in [FLEXUtility allWindows]) {
|
||||
// Don't include the explorer's own window or subviews.
|
||||
if (window != self.view.window && [window pointInside:tapPointInWindow withEvent:nil]) {
|
||||
[views addObject:window];
|
||||
@@ -602,7 +594,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
// Select in the window that would handle the touch, but don't just use the result of hitTest:withEvent: so we can still select views with interaction disabled.
|
||||
// Default to the the application's key window if none of the windows want the touch.
|
||||
UIWindow *windowForSelection = [[UIApplication sharedApplication] keyWindow];
|
||||
for (UIWindow *window in [[self allWindows] reverseObjectEnumerator]) {
|
||||
for (UIWindow *window in [[FLEXUtility allWindows] reverseObjectEnumerator]) {
|
||||
// Ignore the explorer's own window.
|
||||
if (window != self.view.window) {
|
||||
if ([window hitTest:tapPointInWindow withEvent:nil]) {
|
||||
@@ -616,9 +608,9 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
return [[self recursiveSubviewsAtPoint:tapPointInWindow inView:windowForSelection skipHiddenViews:YES] lastObject];
|
||||
}
|
||||
|
||||
- (NSArray *)recursiveSubviewsAtPoint:(CGPoint)pointInView inView:(UIView *)view skipHiddenViews:(BOOL)skipHidden
|
||||
- (NSArray<UIView *> *)recursiveSubviewsAtPoint:(CGPoint)pointInView inView:(UIView *)view skipHiddenViews:(BOOL)skipHidden
|
||||
{
|
||||
NSMutableArray *subviewsAtPoint = [NSMutableArray array];
|
||||
NSMutableArray<UIView *> *subviewsAtPoint = [NSMutableArray array];
|
||||
for (UIView *subview in view.subviews) {
|
||||
BOOL isHidden = subview.hidden || subview.alpha < 0.01;
|
||||
if (skipHidden && isHidden) {
|
||||
@@ -640,9 +632,9 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
return subviewsAtPoint;
|
||||
}
|
||||
|
||||
- (NSArray *)allRecursiveSubviewsInView:(UIView *)view
|
||||
- (NSArray<UIView *> *)allRecursiveSubviewsInView:(UIView *)view
|
||||
{
|
||||
NSMutableArray *subviews = [NSMutableArray array];
|
||||
NSMutableArray<UIView *> *subviews = [NSMutableArray array];
|
||||
for (UIView *subview in view.subviews) {
|
||||
[subviews addObject:subview];
|
||||
[subviews addObjectsFromArray:[self allRecursiveSubviewsInView:subview]];
|
||||
@@ -650,9 +642,9 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
return subviews;
|
||||
}
|
||||
|
||||
- (NSDictionary *)hierarchyDepthsForViews:(NSArray *)views
|
||||
- (NSDictionary<NSValue *, NSNumber *> *)hierarchyDepthsForViews:(NSArray<UIView *> *)views
|
||||
{
|
||||
NSMutableDictionary *hierarchyDepths = [NSMutableDictionary dictionary];
|
||||
NSMutableDictionary<NSValue *, NSNumber *> *hierarchyDepths = [NSMutableDictionary dictionary];
|
||||
for (UIView *view in views) {
|
||||
NSInteger depth = 0;
|
||||
UIView *tryView = view;
|
||||
@@ -696,6 +688,33 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Safe Area Handling
|
||||
|
||||
- (CGRect)viewSafeArea
|
||||
{
|
||||
CGRect safeArea = self.view.bounds;
|
||||
#if FLEX_AT_LEAST_IOS11_SDK
|
||||
if (@available(iOS 11, *)) {
|
||||
safeArea = UIEdgeInsetsInsetRect(self.view.bounds, self.view.safeAreaInsets);
|
||||
}
|
||||
#endif
|
||||
return safeArea;
|
||||
}
|
||||
|
||||
#if FLEX_AT_LEAST_IOS11_SDK
|
||||
- (void)viewSafeAreaInsetsDidChange
|
||||
{
|
||||
if (@available(iOS 11, *)) {
|
||||
[super viewSafeAreaInsetsDidChange];
|
||||
}
|
||||
|
||||
CGRect safeArea = [self viewSafeArea];
|
||||
CGSize toolbarSize = [self.explorerToolbar sizeThatFits:CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(safeArea))];
|
||||
[self updateToolbarPositionWithUnconstrainedFrame:CGRectMake(CGRectGetMinX(self.explorerToolbar.frame), CGRectGetMinY(self.explorerToolbar.frame), toolbarSize.width, toolbarSize.height)];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#pragma mark - Touch Handling
|
||||
|
||||
- (BOOL)shouldReceiveTouchAtWindowPoint:(CGPoint)pointInWindowCoordinates
|
||||
@@ -734,7 +753,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
{
|
||||
// Note that we need to wait until the view controller is dismissed to calculated the frame of the outline view.
|
||||
// Otherwise the coordinate conversion doesn't give the correct result.
|
||||
[self resignKeyAndDismissViewControllerAnimated:YES completion:^{
|
||||
[self toggleViewsToolWithCompletion:^{
|
||||
// If the selected view is outside of the tap point array (selected from "Full Hierarchy"),
|
||||
// then clear out the tap point array and remove all the outline views.
|
||||
if (![self.viewsAtTapPoint containsObject:selectedView]) {
|
||||
@@ -814,6 +833,15 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
return self.previousKeyWindow != nil;
|
||||
}
|
||||
|
||||
- (void)toggleToolWithViewControllerProvider:(UIViewController *(^)(void))future completion:(void(^)(void))completion
|
||||
{
|
||||
if (self.presentedViewController) {
|
||||
[self resignKeyAndDismissViewControllerAnimated:YES completion:completion];
|
||||
} else {
|
||||
[self makeKeyAndPresentViewController:future() animated:YES completion:completion];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Keyboard Shortcut Helpers
|
||||
|
||||
- (void)toggleSelectTool
|
||||
@@ -836,49 +864,32 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
|
||||
- (void)toggleViewsTool
|
||||
{
|
||||
BOOL viewsModalShown = [[self presentedViewController] isKindOfClass:[UINavigationController class]];
|
||||
viewsModalShown = viewsModalShown && [[[(UINavigationController *)[self presentedViewController] viewControllers] firstObject] isKindOfClass:[FLEXHierarchyTableViewController class]];
|
||||
if (viewsModalShown) {
|
||||
[self resignKeyAndDismissViewControllerAnimated:YES completion:nil];
|
||||
} else {
|
||||
void (^presentBlock)() = ^{
|
||||
NSArray *allViews = [self allViewsInHierarchy];
|
||||
NSDictionary *depthsForViews = [self hierarchyDepthsForViews:allViews];
|
||||
FLEXHierarchyTableViewController *hierarchyTVC = [[FLEXHierarchyTableViewController alloc] initWithViews:allViews viewsAtTap:self.viewsAtTapPoint selectedView:self.selectedView depths:depthsForViews];
|
||||
hierarchyTVC.delegate = self;
|
||||
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:hierarchyTVC];
|
||||
[self makeKeyAndPresentViewController:navigationController animated:YES completion:nil];
|
||||
};
|
||||
|
||||
if (self.presentedViewController) {
|
||||
[self resignKeyAndDismissViewControllerAnimated:NO completion:presentBlock];
|
||||
} else {
|
||||
presentBlock();
|
||||
[self toggleViewsToolWithCompletion:nil];
|
||||
}
|
||||
|
||||
- (void)toggleViewsToolWithCompletion:(void(^)(void))completion
|
||||
{
|
||||
[self toggleToolWithViewControllerProvider:^UIViewController *{
|
||||
NSArray<UIView *> *allViews = [self allViewsInHierarchy];
|
||||
NSDictionary *depthsForViews = [self hierarchyDepthsForViews:allViews];
|
||||
FLEXHierarchyTableViewController *hierarchyTVC = [[FLEXHierarchyTableViewController alloc] initWithViews:allViews viewsAtTap:self.viewsAtTapPoint selectedView:self.selectedView depths:depthsForViews];
|
||||
hierarchyTVC.delegate = self;
|
||||
return [[UINavigationController alloc] initWithRootViewController:hierarchyTVC];
|
||||
} completion:^{
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)toggleMenuTool
|
||||
{
|
||||
BOOL menuModalShown = [[self presentedViewController] isKindOfClass:[UINavigationController class]];
|
||||
menuModalShown = menuModalShown && [[[(UINavigationController *)[self presentedViewController] viewControllers] firstObject] isKindOfClass:[FLEXGlobalsTableViewController class]];
|
||||
if (menuModalShown) {
|
||||
[self resignKeyAndDismissViewControllerAnimated:YES completion:nil];
|
||||
} else {
|
||||
void (^presentBlock)() = ^{
|
||||
FLEXGlobalsTableViewController *globalsViewController = [[FLEXGlobalsTableViewController alloc] init];
|
||||
globalsViewController.delegate = self;
|
||||
[FLEXGlobalsTableViewController setApplicationWindow:[[UIApplication sharedApplication] keyWindow]];
|
||||
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:globalsViewController];
|
||||
[self makeKeyAndPresentViewController:navigationController animated:YES completion:nil];
|
||||
};
|
||||
|
||||
if (self.presentedViewController) {
|
||||
[self resignKeyAndDismissViewControllerAnimated:NO completion:presentBlock];
|
||||
} else {
|
||||
presentBlock();
|
||||
}
|
||||
}
|
||||
[self toggleToolWithViewControllerProvider:^UIViewController *{
|
||||
FLEXGlobalsTableViewController *globalsViewController = [[FLEXGlobalsTableViewController alloc] init];
|
||||
globalsViewController.delegate = self;
|
||||
[FLEXGlobalsTableViewController setApplicationWindow:[[UIApplication sharedApplication] keyWindow]];
|
||||
return [[UINavigationController alloc] initWithRootViewController:globalsViewController];
|
||||
} completion:nil];
|
||||
}
|
||||
|
||||
- (void)handleDownArrowKeyPressed
|
||||
@@ -6,12 +6,4 @@
|
||||
// Copyright (c) 2015 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for FLEX.
|
||||
FOUNDATION_EXPORT double FLEXVersionNumber;
|
||||
|
||||
//! Project version string for FLEX.
|
||||
FOUNDATION_EXPORT const unsigned char FLEXVersionString[];
|
||||
|
||||
#import <FLEX/FLEXManager.h>
|
||||
|
||||
@@ -23,13 +23,19 @@
|
||||
|
||||
/// If this property is set to YES, FLEX will swizzle NSURLConnection*Delegate and NSURLSession*Delegate methods
|
||||
/// on classes that conform to the protocols. This allows you to view network activity history from the main FLEX menu.
|
||||
/// Full responses are kept temporarily in a size limited cache and may be pruged under memory pressure.
|
||||
/// Full responses are kept temporarily in a size-limited cache and may be pruned under memory pressure.
|
||||
@property (nonatomic, assign, getter=isNetworkDebuggingEnabled) BOOL networkDebuggingEnabled;
|
||||
|
||||
/// Defaults to 25 MB if never set. Values set here are presisted across launches of the app.
|
||||
/// The response cache uses an NSCache, so it may purge prior to hitting the limit when the app is under memory pressure.
|
||||
@property (nonatomic, assign) NSUInteger networkResponseCacheByteLimit;
|
||||
|
||||
/// Requests whose host ends with one of the blacklisted entries in this array will be not be recorded (eg. google.com).
|
||||
/// Wildcard or subdomain entries are not required (eg. google.com will match any subdomain under google.com).
|
||||
/// Useful to remove requests that are typically noisy, such as analytics requests that you aren't interested in tracking.
|
||||
@property (nonatomic, copy) NSArray<NSString *> *networkRequestHostBlacklist;
|
||||
|
||||
|
||||
#pragma mark - Keyboard Shortcuts
|
||||
|
||||
/// Simulator keyboard shortcuts are enabled by default.
|
||||
@@ -49,6 +55,10 @@
|
||||
|
||||
#pragma mark - Extensions
|
||||
|
||||
/// Default database password is @c nil by default.
|
||||
/// Set this to the password you want the databases to open with.
|
||||
@property (copy, nonatomic) NSString *defaultSqliteDatabasePassword;
|
||||
|
||||
/// Adds an entry at the bottom of the list of Global State items. Call this method before this view controller is displayed.
|
||||
/// @param entryName The string to be displayed in the cell.
|
||||
/// @param objectFutureBlock When you tap on the row, information about the object returned by this block will be displayed.
|
||||
@@ -13,14 +13,14 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface FLEXDatabaseManager : NSObject
|
||||
@protocol FLEXDatabaseManager <NSObject>
|
||||
|
||||
|
||||
- (instancetype)initWithPath:(NSString*)aPath;
|
||||
@required
|
||||
- (instancetype)initWithPath:(NSString*)path;
|
||||
|
||||
- (BOOL)open;
|
||||
- (NSArray *)queryAllTables;
|
||||
- (NSArray *)queryAllColumnsWithTableName:(NSString *)tableName;
|
||||
- (NSArray *)queryAllDataWithTableName:(NSString *)tableName;
|
||||
- (NSArray<NSDictionary<NSString *, id> *> *)queryAllTables;
|
||||
- (NSArray<NSString *> *)queryAllColumnsWithTableName:(NSString *)tableName;
|
||||
- (NSArray<NSDictionary<NSString *, id> *> *)queryAllDataWithTableName:(NSString *)tableName;
|
||||
|
||||
@end
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
@property (nonatomic, strong) UITableView *contentTableView;
|
||||
@property (nonatomic, strong) UIView *leftHeader;
|
||||
|
||||
@property (nonatomic, strong) NSDictionary *sortStatusDict;
|
||||
@property (nonatomic, strong) NSDictionary<NSString *, NSNumber *> *sortStatusDict;
|
||||
@property (nonatomic, strong) NSArray *rowData;
|
||||
@end
|
||||
|
||||
@@ -135,7 +135,7 @@ static const CGFloat kColumnMargin = 1;
|
||||
|
||||
- (void)loadHeaderData
|
||||
{
|
||||
NSArray *subviews = self.headerScrollView.subviews;
|
||||
NSArray<UIView *> *subviews = self.headerScrollView.subviews;
|
||||
|
||||
for (UIView *subview in subviews) {
|
||||
[subview removeFromSuperview];
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// FLEXRealmDatabaseManager.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tim Oliver on 28/01/2016.
|
||||
// Copyright © 2016 Realm. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FLEXDatabaseManager.h"
|
||||
|
||||
@interface FLEXRealmDatabaseManager : NSObject <FLEXDatabaseManager>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,114 @@
|
||||
//
|
||||
// FLEXRealmDatabaseManager.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tim Oliver on 28/01/2016.
|
||||
// Copyright © 2016 Realm. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXRealmDatabaseManager.h"
|
||||
|
||||
#if __has_include(<Realm/Realm.h>)
|
||||
#import <Realm/Realm.h>
|
||||
#import <Realm/RLMRealm_Dynamic.h>
|
||||
#else
|
||||
#import "FLEXRealmDefines.h"
|
||||
#endif
|
||||
|
||||
@interface FLEXRealmDatabaseManager ()
|
||||
|
||||
@property (nonatomic, copy) NSString *path;
|
||||
@property (nonatomic, strong) RLMRealm * realm;
|
||||
|
||||
@end
|
||||
|
||||
//#endif
|
||||
|
||||
@implementation FLEXRealmDatabaseManager
|
||||
|
||||
- (instancetype)initWithPath:(NSString*)aPath
|
||||
{
|
||||
Class realmClass = NSClassFromString(@"RLMRealm");
|
||||
if (realmClass == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
_path = aPath;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)open
|
||||
{
|
||||
Class realmClass = NSClassFromString(@"RLMRealm");
|
||||
Class configurationClass = NSClassFromString(@"RLMRealmConfiguration");
|
||||
|
||||
if (realmClass == nil || configurationClass == nil) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSError *error = nil;
|
||||
id configuration = [[configurationClass alloc] init];
|
||||
[(RLMRealmConfiguration *)configuration setFileURL:[NSURL fileURLWithPath:self.path]];
|
||||
self.realm = [realmClass realmWithConfiguration:configuration error:&error];
|
||||
return (error == nil);
|
||||
}
|
||||
|
||||
- (NSArray<NSDictionary<NSString *, id> *> *)queryAllTables
|
||||
{
|
||||
NSMutableArray<NSDictionary<NSString *, id> *> *allTables = [NSMutableArray array];
|
||||
RLMSchema *schema = [self.realm schema];
|
||||
|
||||
for (RLMObjectSchema *objectSchema in schema.objectSchema) {
|
||||
if (objectSchema.className == nil) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSDictionary<NSString *, id> *dictionary = @{@"name":objectSchema.className};
|
||||
[allTables addObject:dictionary];
|
||||
}
|
||||
|
||||
return allTables;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)queryAllColumnsWithTableName:(NSString *)tableName
|
||||
{
|
||||
RLMObjectSchema *objectSchema = [[self.realm schema] schemaForClassName:tableName];
|
||||
if (objectSchema == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray<NSString *> *columnNames = [NSMutableArray array];
|
||||
for (RLMProperty *property in objectSchema.properties) {
|
||||
[columnNames addObject:property.name];
|
||||
}
|
||||
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
- (NSArray<NSDictionary<NSString *, id> *> *)queryAllDataWithTableName:(NSString *)tableName
|
||||
{
|
||||
RLMObjectSchema *objectSchema = [[self.realm schema] schemaForClassName:tableName];
|
||||
RLMResults *results = [self.realm allObjects:tableName];
|
||||
if (results.count == 0 || objectSchema == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray<NSDictionary<NSString *, id> *> *allDataEntries = [NSMutableArray array];
|
||||
for (RLMObject *result in results) {
|
||||
NSMutableDictionary<NSString *, id> *entry = [NSMutableDictionary dictionary];
|
||||
for (RLMProperty *property in objectSchema.properties) {
|
||||
id value = [result valueForKey:property.name];
|
||||
entry[property.name] = (value) ? (value) : [NSNull null];
|
||||
}
|
||||
|
||||
[allDataEntries addObject:entry];
|
||||
}
|
||||
|
||||
return allDataEntries;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Realm.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tim Oliver on 16/02/2016.
|
||||
// Copyright © 2016 Realm. All rights reserved.
|
||||
//
|
||||
|
||||
#if __has_include(<Realm/Realm.h>)
|
||||
#else
|
||||
|
||||
@class RLMObject, RLMResults, RLMRealm, RLMRealmConfiguration, RLMSchema, RLMObjectSchema, RLMProperty;
|
||||
|
||||
@interface RLMRealmConfiguration : NSObject
|
||||
@property (nonatomic, copy) NSURL *fileURL;
|
||||
@end
|
||||
|
||||
@interface RLMRealm : NSObject
|
||||
@property (nonatomic, readonly) RLMSchema *schema;
|
||||
+ (RLMRealm *)realmWithConfiguration:(RLMRealmConfiguration *)configuration error:(NSError **)error;
|
||||
- (RLMResults *)allObjects:(NSString *)className;
|
||||
@end
|
||||
|
||||
@interface RLMSchema : NSObject
|
||||
@property (nonatomic, readonly) NSArray<RLMObjectSchema *> *objectSchema;
|
||||
- (RLMObjectSchema *)schemaForClassName:(NSString *)className;
|
||||
@end
|
||||
|
||||
@interface RLMObjectSchema : NSObject
|
||||
@property (nonatomic, readonly) NSString *className;
|
||||
@property (nonatomic, readonly) NSArray<RLMProperty *> *properties;
|
||||
@end
|
||||
|
||||
@interface RLMProperty : NSString
|
||||
@property (nonatomic, readonly) NSString *name;
|
||||
@end
|
||||
|
||||
@interface RLMResults : NSObject <NSFastEnumeration>
|
||||
@property (nonatomic, readonly) NSInteger count;
|
||||
@end
|
||||
|
||||
@interface RLMObject : NSObject
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// PTDatabaseManager.h
|
||||
// Derived from:
|
||||
//
|
||||
// FMDatabase.h
|
||||
// FMDB( https://github.com/ccgus/fmdb )
|
||||
//
|
||||
// Created by Peng Tao on 15/11/23.
|
||||
//
|
||||
// Licensed to Flying Meat Inc. under one or more contributor license agreements.
|
||||
// See the LICENSE file distributed with this work for the terms under
|
||||
// which Flying Meat Inc. licenses this file to you.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FLEXDatabaseManager.h"
|
||||
|
||||
@interface FLEXSQLiteDatabaseManager : NSObject <FLEXDatabaseManager>
|
||||
|
||||
@end
|
||||
+25
-17
@@ -6,22 +6,19 @@
|
||||
// Copyright © 2015年 Peng Tao. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "FLEXDatabaseManager.h"
|
||||
#import "FLEXSQLiteDatabaseManager.h"
|
||||
#import "FLEXManager.h"
|
||||
#import <sqlite3.h>
|
||||
|
||||
|
||||
static NSString *const QUERY_TABLENAMES_SQL = @"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
|
||||
|
||||
|
||||
@implementation FLEXDatabaseManager
|
||||
@implementation FLEXSQLiteDatabaseManager
|
||||
{
|
||||
sqlite3* _db;
|
||||
NSString* _databasePath;
|
||||
}
|
||||
|
||||
|
||||
- (instancetype)initWithPath:(NSString*)aPath
|
||||
{
|
||||
self = [super init];
|
||||
@@ -32,12 +29,22 @@ static NSString *const QUERY_TABLENAMES_SQL = @"SELECT name FROM sqlite_master W
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)open {
|
||||
if (_db) {
|
||||
return YES;
|
||||
}
|
||||
int err = sqlite3_open([_databasePath UTF8String], &_db);
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
NSString *defaultSqliteDatabasePassword = [FLEXManager sharedManager].defaultSqliteDatabasePassword;
|
||||
|
||||
if (defaultSqliteDatabasePassword) {
|
||||
const char *key = defaultSqliteDatabasePassword.UTF8String;
|
||||
|
||||
sqlite3_key(_db, key, (int)strlen(key));
|
||||
}
|
||||
#endif
|
||||
|
||||
if(err != SQLITE_OK) {
|
||||
NSLog(@"error opening!: %d", err);
|
||||
return NO;
|
||||
@@ -79,23 +86,24 @@ static NSString *const QUERY_TABLENAMES_SQL = @"SELECT name FROM sqlite_master W
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *)queryAllTables
|
||||
- (NSArray<NSDictionary<NSString *, id> *> *)queryAllTables
|
||||
{
|
||||
return [self executeQuery:QUERY_TABLENAMES_SQL];
|
||||
}
|
||||
|
||||
- (NSArray *)queryAllColumnsWithTableName:(NSString *)tableName
|
||||
- (NSArray<NSString *> *)queryAllColumnsWithTableName:(NSString *)tableName
|
||||
{
|
||||
NSString *sql = [NSString stringWithFormat:@"PRAGMA table_info('%@')",tableName];
|
||||
NSArray *resultArray = [self executeQuery:sql];
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
for (NSDictionary *dict in resultArray) {
|
||||
[array addObject:dict[@"name"]];
|
||||
NSArray<NSDictionary<NSString *, id> *> *resultArray = [self executeQuery:sql];
|
||||
NSMutableArray<NSString *> *array = [NSMutableArray array];
|
||||
for (NSDictionary<NSString *, id> *dict in resultArray) {
|
||||
NSString *columnName = (NSString *)dict[@"name"] ?: @"";
|
||||
[array addObject:columnName];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
- (NSArray *)queryAllDataWithTableName:(NSString *)tableName
|
||||
- (NSArray<NSDictionary<NSString *, id> *> *)queryAllDataWithTableName:(NSString *)tableName
|
||||
{
|
||||
NSString *sql = [NSString stringWithFormat:@"SELECT * FROM %@",tableName];
|
||||
return [self executeQuery:sql];
|
||||
@@ -104,16 +112,16 @@ static NSString *const QUERY_TABLENAMES_SQL = @"SELECT name FROM sqlite_master W
|
||||
#pragma mark -
|
||||
#pragma mark - Private
|
||||
|
||||
- (NSArray *)executeQuery:(NSString *)sql
|
||||
- (NSArray<NSDictionary<NSString *, id> *> *)executeQuery:(NSString *)sql
|
||||
{
|
||||
[self open];
|
||||
NSMutableArray *resultArray = [NSMutableArray array];
|
||||
NSMutableArray<NSDictionary<NSString *, id> *> *resultArray = [NSMutableArray array];
|
||||
sqlite3_stmt *pstmt;
|
||||
if (sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pstmt, 0) == SQLITE_OK) {
|
||||
while (sqlite3_step(pstmt) == SQLITE_ROW) {
|
||||
NSUInteger num_cols = (NSUInteger)sqlite3_data_count(pstmt);
|
||||
if (num_cols > 0) {
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols];
|
||||
NSMutableDictionary<NSString *, id> *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols];
|
||||
|
||||
int columnCount = sqlite3_column_count(pstmt);
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
@interface FLEXTableContentCell : UITableViewCell
|
||||
|
||||
@property (nonatomic, strong)NSArray *labels;
|
||||
@property (nonatomic, strong) NSArray<UILabel *> *labels;
|
||||
|
||||
@property (nonatomic, weak) id<FLEXTableContentCellDelegate>delegate;
|
||||
@property (nonatomic, weak) id<FLEXTableContentCellDelegate> delegate;
|
||||
|
||||
+ (instancetype)cellWithTableView:(UITableView *)tableView columnNumber:(NSInteger)number;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
FLEXTableContentCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
|
||||
if (!cell) {
|
||||
cell = [[FLEXTableContentCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
|
||||
NSMutableArray *labels = [NSMutableArray array];
|
||||
NSMutableArray<UILabel *> *labels = [NSMutableArray array];
|
||||
for (int i = 0; i < number ; i++) {
|
||||
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
|
||||
label.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
@interface FLEXTableContentViewController : UIViewController
|
||||
|
||||
@property (nonatomic, strong) NSArray *columnsArray;
|
||||
@property (nonatomic, strong) NSArray *contentsArray;
|
||||
@property (nonatomic, strong) NSArray<NSString *> *columnsArray;
|
||||
@property (nonatomic, strong) NSArray<NSDictionary<NSString *, id> *> *contentsArray;
|
||||
|
||||
@end
|
||||
|
||||
Regular → Executable
+31
-32
@@ -13,45 +13,39 @@
|
||||
|
||||
@interface FLEXTableContentViewController ()<FLEXMultiColumnTableViewDataSource, FLEXMultiColumnTableViewDelegate>
|
||||
|
||||
@property (nonatomic, strong)FLEXMultiColumnTableView *multiColumView;
|
||||
@property (nonatomic, strong) FLEXMultiColumnTableView *multiColumView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXTableContentViewController
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
|
||||
CGRect rectStatus = [UIApplication sharedApplication].statusBarFrame;
|
||||
CGFloat y = 64;
|
||||
if (rectStatus.size.height == 0) {
|
||||
y = 32;
|
||||
}
|
||||
_multiColumView = [[FLEXMultiColumnTableView alloc] initWithFrame:
|
||||
CGRectMake(0, y, self.view.frame.size.width, self.view.frame.size.height - y)];
|
||||
|
||||
_multiColumView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
_multiColumView.backgroundColor = [UIColor whiteColor];
|
||||
_multiColumView.dataSource = self;
|
||||
_multiColumView.delegate = self;
|
||||
self.automaticallyAdjustsScrollViewInsets = NO;
|
||||
|
||||
|
||||
[self.view addSubview:_multiColumView];
|
||||
}
|
||||
return self;
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.edgesForExtendedLayout = UIRectEdgeNone;
|
||||
[self.view addSubview:self.multiColumView];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
[self.multiColumView reloadData];
|
||||
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
#pragma mark init SubView
|
||||
- (FLEXMultiColumnTableView *)multiColumView {
|
||||
if (!_multiColumView) {
|
||||
_multiColumView = [[FLEXMultiColumnTableView alloc] initWithFrame:
|
||||
CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
|
||||
|
||||
_multiColumView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin;
|
||||
_multiColumView.backgroundColor = [UIColor whiteColor];
|
||||
_multiColumView.dataSource = self;
|
||||
_multiColumView.delegate = self;
|
||||
}
|
||||
return _multiColumView;
|
||||
}
|
||||
#pragma mark MultiColumnTableView DataSource
|
||||
|
||||
- (NSInteger)numberOfColumnsInTableView:(FLEXMultiColumnTableView *)tableView
|
||||
@@ -78,7 +72,7 @@
|
||||
- (NSString *)contentAtColumn:(NSInteger)column row:(NSInteger)row
|
||||
{
|
||||
if (self.contentsArray.count > row) {
|
||||
NSDictionary *dic = self.contentsArray[row];
|
||||
NSDictionary<NSString *, id> *dic = self.contentsArray[row];
|
||||
if (self.contentsArray.count > column) {
|
||||
return [NSString stringWithFormat:@"%@",[dic objectForKey:self.columnsArray[column]]];
|
||||
}
|
||||
@@ -90,11 +84,11 @@
|
||||
{
|
||||
NSMutableArray *result = [NSMutableArray array];
|
||||
if (self.contentsArray.count > row) {
|
||||
NSDictionary *dic = self.contentsArray[row];
|
||||
NSDictionary<NSString *, id> *dic = self.contentsArray[row];
|
||||
for (int i = 0; i < self.columnsArray.count; i ++) {
|
||||
[result addObject:dic[self.columnsArray[i]]];
|
||||
}
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
@@ -119,7 +113,7 @@
|
||||
- (CGFloat)widthForLeftHeaderInTableView:(FLEXMultiColumnTableView *)tableView
|
||||
{
|
||||
NSString *str = [NSString stringWithFormat:@"%lu",(unsigned long)self.contentsArray.count];
|
||||
NSDictionary *attrs = @{@"NSFontAttributeName":[UIFont systemFontOfSize:17.0]};
|
||||
NSDictionary<NSString *, id> *attrs = @{@"NSFontAttributeName":[UIFont systemFontOfSize:17.0]};
|
||||
CGSize size = [str boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 14)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin
|
||||
attributes:attrs context:nil].size;
|
||||
@@ -139,7 +133,7 @@
|
||||
- (void)multiColumnTableView:(FLEXMultiColumnTableView *)tableView didTapHeaderWithText:(NSString *)text sortType:(FLEXTableColumnHeaderSortType)sortType
|
||||
{
|
||||
|
||||
NSArray *sortContentData = [self.contentsArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
|
||||
NSArray<NSDictionary<NSString *, id> *> *sortContentData = [self.contentsArray sortedArrayUsingComparator:^NSComparisonResult(NSDictionary<NSString *, id> * obj1, NSDictionary<NSString *, id> * obj2) {
|
||||
|
||||
if ([obj1 objectForKey:text] == [NSNull null]) {
|
||||
return NSOrderedAscending;
|
||||
@@ -147,6 +141,11 @@
|
||||
if ([obj2 objectForKey:text] == [NSNull null]) {
|
||||
return NSOrderedDescending;
|
||||
}
|
||||
|
||||
if (![[obj1 objectForKey:text] respondsToSelector:@selector(compare:)] && ![[obj2 objectForKey:text] respondsToSelector:@selector(compare:)]) {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
|
||||
NSComparisonResult result = [[obj1 objectForKey:text] compare:[obj2 objectForKey:text]];
|
||||
|
||||
return result;
|
||||
@@ -171,10 +170,10 @@
|
||||
[coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) {
|
||||
if (newCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {
|
||||
|
||||
_multiColumView.frame = CGRectMake(0, 32, self.view.frame.size.width, self.view.frame.size.height - 32);
|
||||
self->_multiColumView.frame = CGRectMake(0, 32, self.view.frame.size.width, self.view.frame.size.height - 32);
|
||||
}
|
||||
else {
|
||||
_multiColumView.frame = CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 64);
|
||||
self->_multiColumView.frame = CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 64);
|
||||
}
|
||||
[self.view setNeedsLayout];
|
||||
} completion:nil];
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
@interface FLEXTableListViewController : UITableViewController
|
||||
|
||||
+ (BOOL)supportsExtension:(NSString *)extension;
|
||||
- (instancetype)initWithPath:(NSString *)path;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,40 +7,64 @@
|
||||
//
|
||||
|
||||
#import "FLEXTableListViewController.h"
|
||||
|
||||
#import "FLEXDatabaseManager.h"
|
||||
#import "FLEXSQLiteDatabaseManager.h"
|
||||
#import "FLEXRealmDatabaseManager.h"
|
||||
|
||||
#import "FLEXTableContentViewController.h"
|
||||
|
||||
@interface FLEXTableListViewController ()
|
||||
{
|
||||
FLEXDatabaseManager *_dbm;
|
||||
id<FLEXDatabaseManager> _dbm;
|
||||
NSString *_databasePath;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) NSArray *tables;
|
||||
@property (nonatomic, strong) NSArray<NSString *> *tables;
|
||||
|
||||
+ (NSArray<NSString *> *)supportedSQLiteExtensions;
|
||||
+ (NSArray<NSString *> *)supportedRealmExtensions;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXTableListViewController
|
||||
|
||||
|
||||
- (instancetype)initWithPath:(NSString *)path
|
||||
{
|
||||
self = [super initWithStyle:UITableViewStyleGrouped];
|
||||
if (self) {
|
||||
_databasePath = [path copy];
|
||||
_dbm = [[FLEXDatabaseManager alloc] initWithPath:path];
|
||||
_dbm = [self databaseManagerForFileAtPath:_databasePath];
|
||||
[_dbm open];
|
||||
[self getAllTables];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id<FLEXDatabaseManager>)databaseManagerForFileAtPath:(NSString *)path
|
||||
{
|
||||
NSString *pathExtension = path.pathExtension.lowercaseString;
|
||||
|
||||
NSArray<NSString *> *sqliteExtensions = [FLEXTableListViewController supportedSQLiteExtensions];
|
||||
if ([sqliteExtensions indexOfObject:pathExtension] != NSNotFound) {
|
||||
return [[FLEXSQLiteDatabaseManager alloc] initWithPath:path];
|
||||
}
|
||||
|
||||
NSArray<NSString *> *realmExtensions = [FLEXTableListViewController supportedRealmExtensions];
|
||||
if (realmExtensions != nil && [realmExtensions indexOfObject:pathExtension] != NSNotFound) {
|
||||
return [[FLEXRealmDatabaseManager alloc] initWithPath:path];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)getAllTables
|
||||
{
|
||||
NSArray *resultArray = [_dbm queryAllTables];
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
for (NSDictionary *dict in resultArray) {
|
||||
[array addObject:dict[@"name"]];
|
||||
NSArray<NSDictionary<NSString *, id> *> *resultArray = [_dbm queryAllTables];
|
||||
NSMutableArray<NSString *> *array = [NSMutableArray array];
|
||||
for (NSDictionary<NSString *, id> *dict in resultArray) {
|
||||
NSString *columnName = (NSString *)dict[@"name"] ?: @"";
|
||||
[array addObject:columnName];
|
||||
}
|
||||
self.tables = array;
|
||||
}
|
||||
@@ -79,4 +103,35 @@
|
||||
return [NSString stringWithFormat:@"%lu tables", (unsigned long)self.tables.count];
|
||||
}
|
||||
|
||||
+ (BOOL)supportsExtension:(NSString *)extension
|
||||
{
|
||||
extension = extension.lowercaseString;
|
||||
|
||||
NSArray<NSString *> *sqliteExtensions = [FLEXTableListViewController supportedSQLiteExtensions];
|
||||
if (sqliteExtensions.count > 0 && [sqliteExtensions indexOfObject:extension] != NSNotFound) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSArray<NSString *> *realmExtensions = [FLEXTableListViewController supportedRealmExtensions];
|
||||
if (realmExtensions.count > 0 && [realmExtensions indexOfObject:extension] != NSNotFound) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (NSArray<NSString *> *)supportedSQLiteExtensions
|
||||
{
|
||||
return @[@"db", @"sqlite", @"sqlite3"];
|
||||
}
|
||||
|
||||
+ (NSArray<NSString *> *)supportedRealmExtensions
|
||||
{
|
||||
if (NSClassFromString(@"RLMRealm") == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return @[@"realm"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
@interface FLEXClassesTableViewController () <UISearchBarDelegate>
|
||||
|
||||
@property (nonatomic, strong) NSArray *classNames;
|
||||
@property (nonatomic, strong) NSArray *filteredClassNames;
|
||||
@property (nonatomic, strong) NSArray<NSString *> *classNames;
|
||||
@property (nonatomic, strong) NSArray<NSString *> *filteredClassNames;
|
||||
@property (nonatomic, strong) UISearchBar *searchBar;
|
||||
|
||||
@end
|
||||
@@ -42,7 +42,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setClassNames:(NSArray *)classNames
|
||||
- (void)setClassNames:(NSArray<NSString *> *)classNames
|
||||
{
|
||||
_classNames = classNames;
|
||||
self.filteredClassNames = classNames;
|
||||
@@ -53,7 +53,7 @@
|
||||
unsigned int classNamesCount = 0;
|
||||
const char **classNames = objc_copyClassNamesForImage([self.binaryImageName UTF8String], &classNamesCount);
|
||||
if (classNames) {
|
||||
NSMutableArray *classNameStrings = [NSMutableArray array];
|
||||
NSMutableArray<NSString *> *classNameStrings = [NSMutableArray array];
|
||||
for (unsigned int i = 0; i < classNamesCount; i++) {
|
||||
const char *className = classNames[i];
|
||||
NSString *classNameString = [NSString stringWithUTF8String:className];
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
- (void)updateTitle
|
||||
{
|
||||
NSString *shortImageName = [[self.binaryImageName componentsSeparatedByString:@"/"] lastObject];
|
||||
NSString *shortImageName = self.binaryImageName.lastPathComponent;
|
||||
self.title = [NSString stringWithFormat:@"%@ Classes (%lu)", shortImageName, (unsigned long)[self.filteredClassNames count]];
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
@interface FLEXCookiesTableViewController ()
|
||||
|
||||
@property (nonatomic, strong) NSArray *cookies;
|
||||
@property (nonatomic, strong) NSArray<NSHTTPCookie *> *cookies;
|
||||
|
||||
@end
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
self.title = @"Cookies";
|
||||
|
||||
NSSortDescriptor *nameSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)];
|
||||
_cookies =[[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies sortedArrayUsingDescriptors:@[nameSortDescriptor]];
|
||||
_cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies sortedArrayUsingDescriptors:@[nameSortDescriptor]];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
|
||||
@protocol FLEXFileBrowserSearchOperationDelegate <NSObject>
|
||||
|
||||
- (void)fileBrowserSearchOperationResult:(NSArray *)searchResult size:(uint64_t)size;
|
||||
- (void)fileBrowserSearchOperationResult:(NSArray<NSString *> *)searchResult size:(uint64_t)size;
|
||||
|
||||
@end
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
- (uint64_t)totalSizeAtPath:(NSString *)path
|
||||
{
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSDictionary *attributes = [fileManager attributesOfItemAtPath:path error:NULL];
|
||||
NSDictionary<NSString *, id> *attributes = [fileManager attributesOfItemAtPath:path error:NULL];
|
||||
uint64_t totalSize = [attributes fileSize];
|
||||
|
||||
for (NSString *fileName in [fileManager enumeratorAtPath:path]) {
|
||||
@@ -65,16 +65,16 @@
|
||||
- (void)main
|
||||
{
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSMutableArray *searchPaths = [NSMutableArray array];
|
||||
NSMutableDictionary *sizeMapping = [NSMutableDictionary dictionary];
|
||||
NSMutableArray<NSString *> *searchPaths = [NSMutableArray array];
|
||||
NSMutableDictionary<NSString *, NSNumber *> *sizeMapping = [NSMutableDictionary dictionary];
|
||||
uint64_t totalSize = 0;
|
||||
NSMutableArray *stack = [NSMutableArray array];
|
||||
NSMutableArray<NSString *> *stack = [NSMutableArray array];
|
||||
[stack flex_push:self.path];
|
||||
|
||||
//recursive found all match searchString paths, and precomputing there size
|
||||
while ([stack count]) {
|
||||
NSString *currentPath = [stack flex_pop];
|
||||
NSArray *directoryPath = [fileManager contentsOfDirectoryAtPath:currentPath error:nil];
|
||||
NSArray<NSString *> *directoryPath = [fileManager contentsOfDirectoryAtPath:currentPath error:nil];
|
||||
|
||||
for (NSString *subPath in directoryPath) {
|
||||
NSString *fullPath = [currentPath stringByAppendingPathComponent:subPath];
|
||||
@@ -99,7 +99,7 @@
|
||||
}
|
||||
|
||||
//sort
|
||||
NSArray *sortedArray = [searchPaths sortedArrayUsingComparator:^NSComparisonResult(NSString *path1, NSString *path2) {
|
||||
NSArray<NSString *> *sortedArray = [searchPaths sortedArrayUsingComparator:^NSComparisonResult(NSString *path1, NSString *path2) {
|
||||
uint64_t pathSize1 = [sizeMapping[path1] unsignedLongLongValue];
|
||||
uint64_t pathSize2 = [sizeMapping[path2] unsignedLongLongValue];
|
||||
if (pathSize1 < pathSize2) {
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
@interface FLEXFileBrowserTableViewController () <FLEXFileBrowserFileOperationControllerDelegate, FLEXFileBrowserSearchOperationDelegate, UISearchResultsUpdating, UISearchControllerDelegate>
|
||||
|
||||
@property (nonatomic, copy) NSString *path;
|
||||
@property (nonatomic, copy) NSArray *childPaths;
|
||||
@property (nonatomic, strong) NSArray *searchPaths;
|
||||
@property (nonatomic, copy) NSArray<NSString *> *childPaths;
|
||||
@property (nonatomic, strong) NSArray<NSString *> *searchPaths;
|
||||
@property (nonatomic, strong) NSNumber *recursiveSize;
|
||||
@property (nonatomic, strong) NSNumber *searchPathsSize;
|
||||
@property (nonatomic, strong) UISearchController *searchController;
|
||||
@@ -44,30 +44,30 @@
|
||||
self.path = path;
|
||||
self.title = [path lastPathComponent];
|
||||
self.operationQueue = [NSOperationQueue new];
|
||||
|
||||
|
||||
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
|
||||
self.searchController.searchResultsUpdater = self;
|
||||
self.searchController.delegate = self;
|
||||
self.searchController.dimsBackgroundDuringPresentation = NO;
|
||||
self.tableView.tableHeaderView = self.searchController.searchBar;
|
||||
|
||||
|
||||
//computing path size
|
||||
FLEXFileBrowserTableViewController *__weak weakSelf = self;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSDictionary *attributes = [fileManager attributesOfItemAtPath:path error:NULL];
|
||||
NSDictionary<NSString *, id> *attributes = [fileManager attributesOfItemAtPath:path error:NULL];
|
||||
uint64_t totalSize = [attributes fileSize];
|
||||
|
||||
|
||||
for (NSString *fileName in [fileManager enumeratorAtPath:path]) {
|
||||
attributes = [fileManager attributesOfItemAtPath:[path stringByAppendingPathComponent:fileName] error:NULL];
|
||||
totalSize += [attributes fileSize];
|
||||
|
||||
|
||||
// Bail if the interested view controller has gone away.
|
||||
if (!weakSelf) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
FLEXFileBrowserTableViewController *__strong strongSelf = weakSelf;
|
||||
strongSelf.recursiveSize = @(totalSize);
|
||||
@@ -86,14 +86,11 @@
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
UIMenuItem *renameMenuItem = [[UIMenuItem alloc] initWithTitle:@"Rename" action:@selector(fileBrowserRename:)];
|
||||
UIMenuItem *deleteMenuItem = [[UIMenuItem alloc] initWithTitle:@"Delete" action:@selector(fileBrowserDelete:)];
|
||||
[UIMenuController sharedMenuController].menuItems = @[renameMenuItem, deleteMenuItem];
|
||||
}
|
||||
|
||||
#pragma mark - FLEXFileBrowserSearchOperationDelegate
|
||||
|
||||
- (void)fileBrowserSearchOperationResult:(NSArray *)searchResult size:(uint64_t)size
|
||||
- (void)fileBrowserSearchOperationResult:(NSArray<NSString *> *)searchResult size:(uint64_t)size
|
||||
{
|
||||
self.searchPaths = searchResult;
|
||||
self.searchPathsSize = @(size);
|
||||
@@ -133,22 +130,22 @@
|
||||
{
|
||||
BOOL isSearchActive = self.searchController.isActive;
|
||||
NSNumber *currentSize = isSearchActive ? self.searchPathsSize : self.recursiveSize;
|
||||
NSArray *currentPaths = isSearchActive ? self.searchPaths : self.childPaths;
|
||||
|
||||
NSArray<NSString *> *currentPaths = isSearchActive ? self.searchPaths : self.childPaths;
|
||||
|
||||
NSString *sizeString = nil;
|
||||
if (!currentSize) {
|
||||
sizeString = @"Computing size…";
|
||||
} else {
|
||||
sizeString = [NSByteCountFormatter stringFromByteCount:[currentSize longLongValue] countStyle:NSByteCountFormatterCountStyleFile];
|
||||
}
|
||||
|
||||
|
||||
return [NSString stringWithFormat:@"%lu files (%@)", (unsigned long)[currentPaths count], sizeString];
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
NSString *fullPath = [self filePathAtIndexPath:indexPath];
|
||||
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fullPath error:NULL];
|
||||
NSDictionary<NSString *, id> *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fullPath error:NULL];
|
||||
BOOL isDirectory = [[attributes fileType] isEqual:NSFileTypeDirectory];
|
||||
NSString *subtitle = nil;
|
||||
if (isDirectory) {
|
||||
@@ -158,15 +155,15 @@
|
||||
NSString *sizeString = [NSByteCountFormatter stringFromByteCount:[attributes fileSize] countStyle:NSByteCountFormatterCountStyleFile];
|
||||
subtitle = [NSString stringWithFormat:@"%@ - %@", sizeString, [attributes fileModificationDate]];
|
||||
}
|
||||
|
||||
|
||||
static NSString *textCellIdentifier = @"textCell";
|
||||
static NSString *imageCellIdentifier = @"imageCell";
|
||||
UITableViewCell *cell = nil;
|
||||
|
||||
|
||||
// Separate image and text only cells because otherwise the separator lines get out-of-whack on image cells reused with text only.
|
||||
BOOL showImagePreview = [FLEXUtility isImagePathExtension:[fullPath pathExtension]];
|
||||
NSString *cellIdentifier = showImagePreview ? imageCellIdentifier : textCellIdentifier;
|
||||
|
||||
|
||||
if (!cell) {
|
||||
cell = [[FLEXFileBrowserTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
|
||||
cell.textLabel.font = [FLEXUtility defaultTableViewCellLabelFont];
|
||||
@@ -177,12 +174,12 @@
|
||||
NSString *cellTitle = [fullPath lastPathComponent];
|
||||
cell.textLabel.text = cellTitle;
|
||||
cell.detailTextLabel.text = subtitle;
|
||||
|
||||
|
||||
if (showImagePreview) {
|
||||
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
cell.imageView.image = [UIImage imageWithContentsOfFile:fullPath];
|
||||
}
|
||||
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
@@ -190,34 +187,35 @@
|
||||
{
|
||||
NSString *fullPath = [self filePathAtIndexPath:indexPath];
|
||||
NSString *subpath = [fullPath lastPathComponent];
|
||||
|
||||
NSString *pathExtension = [subpath pathExtension];
|
||||
|
||||
BOOL isDirectory = NO;
|
||||
BOOL stillExists = [[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:&isDirectory];
|
||||
if (stillExists) {
|
||||
UIViewController *drillInViewController = nil;
|
||||
if (isDirectory) {
|
||||
drillInViewController = [[[self class] alloc] initWithPath:fullPath];
|
||||
} else if ([FLEXUtility isImagePathExtension:[fullPath pathExtension]]) {
|
||||
} else if ([FLEXUtility isImagePathExtension:pathExtension]) {
|
||||
UIImage *image = [UIImage imageWithContentsOfFile:fullPath];
|
||||
drillInViewController = [[FLEXImagePreviewViewController alloc] initWithImage:image];
|
||||
} else {
|
||||
// Special case keyed archives, json, and plists to get more readable data.
|
||||
NSString *prettyString = nil;
|
||||
if ([[subpath pathExtension] isEqual:@"archive"]) {
|
||||
if ([pathExtension isEqual:@"archive"] || [pathExtension isEqual:@"coded"]) {
|
||||
prettyString = [[NSKeyedUnarchiver unarchiveObjectWithFile:fullPath] description];
|
||||
} else if ([[subpath pathExtension] isEqualToString:@"json"]) {
|
||||
} else if ([pathExtension isEqualToString:@"json"]) {
|
||||
prettyString = [FLEXUtility prettyJSONStringFromData:[NSData dataWithContentsOfFile:fullPath]];
|
||||
} else if ([[subpath pathExtension] isEqualToString:@"plist"]) {
|
||||
} else if ([pathExtension isEqualToString:@"plist"]) {
|
||||
NSData *fileData = [NSData dataWithContentsOfFile:fullPath];
|
||||
prettyString = [[NSPropertyListSerialization propertyListWithData:fileData options:0 format:NULL error:NULL] description];
|
||||
}
|
||||
|
||||
|
||||
if ([prettyString length] > 0) {
|
||||
drillInViewController = [[FLEXWebViewController alloc] initWithText:prettyString];
|
||||
} else if ([FLEXWebViewController supportsPathExtension:[subpath pathExtension]]) {
|
||||
} else if ([FLEXWebViewController supportsPathExtension:pathExtension]) {
|
||||
drillInViewController = [[FLEXWebViewController alloc] initWithURL:[NSURL fileURLWithPath:fullPath]];
|
||||
} else if ([[subpath pathExtension] isEqualToString:@"db"]) {
|
||||
drillInViewController = [[FLEXTableListViewController alloc] initWithPath:fullPath];
|
||||
} else if ([FLEXTableListViewController supportsExtension:subpath.pathExtension]) {
|
||||
drillInViewController = [[FLEXTableListViewController alloc] initWithPath:fullPath];
|
||||
}
|
||||
else {
|
||||
NSString *fileString = [NSString stringWithContentsOfFile:fullPath encoding:NSUTF8StringEncoding error:NULL];
|
||||
@@ -226,7 +224,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (drillInViewController) {
|
||||
drillInViewController.title = [subpath lastPathComponent];
|
||||
[self.navigationController pushViewController:drillInViewController animated:YES];
|
||||
@@ -242,12 +240,25 @@
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UIMenuItem *renameMenuItem = [[UIMenuItem alloc] initWithTitle:@"Rename" action:@selector(fileBrowserRename:)];
|
||||
UIMenuItem *deleteMenuItem = [[UIMenuItem alloc] initWithTitle:@"Delete" action:@selector(fileBrowserDelete:)];
|
||||
NSMutableArray *menus = [NSMutableArray arrayWithObjects:renameMenuItem, deleteMenuItem, nil];
|
||||
|
||||
NSString *fullPath = [self filePathAtIndexPath:indexPath];
|
||||
NSError *error = nil;
|
||||
NSDictionary *attributes = [NSFileManager.defaultManager attributesOfItemAtPath:fullPath error:&error];
|
||||
if (error == nil && [attributes fileType] != NSFileTypeDirectory) {
|
||||
UIMenuItem *shareMenuItem = [[UIMenuItem alloc] initWithTitle:@"Share" action:@selector(fileBrowserShare:)];
|
||||
[menus addObject:shareMenuItem];
|
||||
}
|
||||
[UIMenuController sharedMenuController].menuItems = menus;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
|
||||
{
|
||||
return action == @selector(fileBrowserDelete:) || action == @selector(fileBrowserRename:);
|
||||
return action == @selector(fileBrowserDelete:) || action == @selector(fileBrowserRename:) || action == @selector(fileBrowserShare:);
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
|
||||
@@ -287,12 +298,21 @@
|
||||
{
|
||||
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
|
||||
NSString *fullPath = [self filePathAtIndexPath:indexPath];
|
||||
|
||||
|
||||
self.fileOperationController = [[FLEXFileBrowserFileDeleteOperationController alloc] initWithPath:fullPath];
|
||||
self.fileOperationController.delegate = self;
|
||||
[self.fileOperationController show];
|
||||
}
|
||||
|
||||
- (void)fileBrowserShare:(UITableViewCell *)sender
|
||||
{
|
||||
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
|
||||
NSString *fullPath = [self filePathAtIndexPath:indexPath];
|
||||
|
||||
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[fullPath] applicationActivities:nil];
|
||||
[self presentViewController:activityViewController animated:true completion:nil];
|
||||
}
|
||||
|
||||
- (void)reloadDisplayedPaths
|
||||
{
|
||||
if (self.searchController.isActive) {
|
||||
@@ -305,8 +325,8 @@
|
||||
|
||||
- (void)reloadChildPaths
|
||||
{
|
||||
NSMutableArray *childPaths = [NSMutableArray array];
|
||||
NSArray *subpaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.path error:NULL];
|
||||
NSMutableArray<NSString *> *childPaths = [NSMutableArray array];
|
||||
NSArray<NSString *> *subpaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.path error:NULL];
|
||||
for (NSString *subpath in subpaths) {
|
||||
[childPaths addObject:[self.path stringByAppendingPathComponent:subpath]];
|
||||
}
|
||||
@@ -347,4 +367,10 @@
|
||||
[[UIApplication sharedApplication] sendAction:_cmd to:target from:self forEvent:nil];
|
||||
}
|
||||
|
||||
- (void)fileBrowserShare:(UIMenuController *)sender
|
||||
{
|
||||
id target = [self.nextResponder targetForAction:_cmd withSender:sender];
|
||||
[[UIApplication sharedApplication] sendAction:_cmd to:target from:self forEvent:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -33,6 +33,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
|
||||
FLEXGlobalsRowAppDelegate,
|
||||
FLEXGlobalsRowRootViewController,
|
||||
FLEXGlobalsRowUserDefaults,
|
||||
FLEXGlobalsRowMainBundle,
|
||||
FLEXGlobalsRowApplication,
|
||||
FLEXGlobalsRowKeyWindow,
|
||||
FLEXGlobalsRowMainScreen,
|
||||
@@ -42,17 +43,15 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
|
||||
|
||||
@interface FLEXGlobalsTableViewController ()
|
||||
|
||||
/// [FLEXGlobalsTableViewControllerEntry *]
|
||||
@property (nonatomic, readonly, copy) NSArray *entries;
|
||||
@property (nonatomic, readonly, copy) NSArray<FLEXGlobalsTableViewControllerEntry *> *entries;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXGlobalsTableViewController
|
||||
|
||||
/// [FLEXGlobalsTableViewControllerEntry *]
|
||||
+ (NSArray *)defaultGlobalEntries
|
||||
+ (NSArray<FLEXGlobalsTableViewControllerEntry *> *)defaultGlobalEntries
|
||||
{
|
||||
NSMutableArray *defaultGlobalEntries = [NSMutableArray array];
|
||||
NSMutableArray<FLEXGlobalsTableViewControllerEntry *> *defaultGlobalEntries = [NSMutableArray array];
|
||||
|
||||
for (FLEXGlobalsRow defaultRowIndex = 0; defaultRowIndex < FLEXGlobalsRowCount; defaultRowIndex++) {
|
||||
FLEXGlobalsTableViewControllerEntryNameFuture titleFuture = nil;
|
||||
@@ -125,6 +124,16 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
|
||||
};
|
||||
break;
|
||||
|
||||
case FLEXGlobalsRowMainBundle:
|
||||
titleFuture = ^NSString *{
|
||||
return @"📦 +[NSBundle mainBundle]";
|
||||
};
|
||||
viewControllerFuture = ^UIViewController *{
|
||||
NSBundle *mainBundle = [NSBundle mainBundle];
|
||||
return [FLEXObjectExplorerFactory explorerViewControllerForObject:mainBundle];
|
||||
};
|
||||
break;
|
||||
|
||||
case FLEXGlobalsRowApplication:
|
||||
titleFuture = ^NSString *{
|
||||
return @"💾 +[UIApplication sharedApplication]";
|
||||
|
||||
@@ -12,16 +12,49 @@
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXHeapEnumerator.h"
|
||||
#import "FLEXObjectRef.h"
|
||||
#import <malloc/malloc.h>
|
||||
|
||||
|
||||
@interface FLEXInstancesTableViewController ()
|
||||
|
||||
@property (nonatomic, strong) NSArray *instances;
|
||||
@property (nonatomic, strong) NSArray *fieldNames;
|
||||
/// Array of [[section], [section], ...]
|
||||
/// where [section] is [["row title", instance], ["row title", instance], ...]
|
||||
@property (nonatomic) NSArray<FLEXObjectRef *> *instances;
|
||||
@property (nonatomic) NSArray<NSArray<FLEXObjectRef*>*> *sections;
|
||||
@property (nonatomic) NSArray<NSString *> *sectionTitles;
|
||||
@property (nonatomic) NSArray<NSPredicate *> *predicates;
|
||||
@property (nonatomic, readonly) NSInteger maxSections;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXInstancesTableViewController
|
||||
|
||||
- (id)initWithReferences:(NSArray<FLEXObjectRef *> *)references {
|
||||
return [self initWithReferences:references predicates:nil sectionTitles:nil];
|
||||
}
|
||||
|
||||
- (id)initWithReferences:(NSArray<FLEXObjectRef *> *)references
|
||||
predicates:(NSArray<NSPredicate *> *)predicates
|
||||
sectionTitles:(NSArray<NSString *> *)sectionTitles {
|
||||
NSParameterAssert(predicates.count == sectionTitles.count);
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.instances = references;
|
||||
self.predicates = predicates;
|
||||
self.sectionTitles = sectionTitles;
|
||||
|
||||
if (predicates.count) {
|
||||
[self buildSections];
|
||||
} else {
|
||||
self.sections = @[references];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)instancesTableViewControllerForClassName:(NSString *)className
|
||||
{
|
||||
const char *classNameCString = [className UTF8String];
|
||||
@@ -31,19 +64,20 @@
|
||||
// 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.
|
||||
[instances addObject:object];
|
||||
if (malloc_size((__bridge const void *)(object)) > 0) {
|
||||
[instances addObject:object];
|
||||
}
|
||||
}
|
||||
}];
|
||||
FLEXInstancesTableViewController *instancesViewController = [[self alloc] init];
|
||||
instancesViewController.instances = instances;
|
||||
instancesViewController.title = [NSString stringWithFormat:@"%@ (%lu)", className, (unsigned long)[instances count]];
|
||||
return instancesViewController;
|
||||
NSArray<FLEXObjectRef *> *references = [FLEXObjectRef referencingAll:instances];
|
||||
FLEXInstancesTableViewController *viewController = [[self alloc] initWithReferences:references];
|
||||
viewController.title = [NSString stringWithFormat:@"%@ (%lu)", className, (unsigned long)[instances count]];
|
||||
return viewController;
|
||||
}
|
||||
|
||||
+ (instancetype)instancesTableViewControllerForInstancesReferencingObject:(id)object
|
||||
{
|
||||
NSMutableArray *instances = [NSMutableArray array];
|
||||
NSMutableArray *fieldNames = [NSMutableArray array];
|
||||
NSMutableArray<FLEXObjectRef *> *instances = [NSMutableArray array];
|
||||
[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.
|
||||
@@ -58,8 +92,7 @@
|
||||
ptrdiff_t offset = ivar_getOffset(ivar);
|
||||
uintptr_t *fieldPointer = (__bridge void *)tryObject + offset;
|
||||
if (*fieldPointer == (uintptr_t)(__bridge void *)object) {
|
||||
[instances addObject:tryObject];
|
||||
[fieldNames addObject:@(ivar_getName(ivar))];
|
||||
[instances addObject:[FLEXObjectRef referencing:tryObject ivar:@(ivar_getName(ivar))]];
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -67,11 +100,85 @@
|
||||
tryClass = class_getSuperclass(tryClass);
|
||||
}
|
||||
}];
|
||||
FLEXInstancesTableViewController *instancesViewController = [[self alloc] init];
|
||||
instancesViewController.instances = instances;
|
||||
instancesViewController.fieldNames = fieldNames;
|
||||
instancesViewController.title = [NSString stringWithFormat:@"Referencing %@ %p", NSStringFromClass(object_getClass(object)), object];
|
||||
return instancesViewController;
|
||||
|
||||
NSArray<NSPredicate *> *predicates = [self defaultPredicates];
|
||||
NSArray<NSString *> *sectionTitles = [self defaultSectionTitles];
|
||||
FLEXInstancesTableViewController *viewController = [[self alloc] initWithReferences:instances
|
||||
predicates:predicates
|
||||
sectionTitles:sectionTitles];
|
||||
viewController.title = [NSString stringWithFormat:@"Referencing %@ %p", NSStringFromClass(object_getClass(object)), object];
|
||||
return viewController;
|
||||
}
|
||||
|
||||
+ (NSPredicate *)defaultPredicateForSection:(NSInteger)section
|
||||
{
|
||||
// These are the types of references that we typically don't care about.
|
||||
// We want this list of "object-ivar pairs" split into two sections.
|
||||
BOOL(^isObserver)(FLEXObjectRef *, NSDictionary *) = ^BOOL(FLEXObjectRef *ref, NSDictionary *bindings) {
|
||||
NSString *row = ref.reference;
|
||||
return [row isEqualToString:@"__NSObserver object"] ||
|
||||
[row isEqualToString:@"_CFXNotificationObjcObserverRegistration _object"];
|
||||
};
|
||||
|
||||
/// These are common AutoLayout related references we also rarely care about.
|
||||
BOOL(^isConstraintRelated)(FLEXObjectRef *, NSDictionary *) = ^BOOL(FLEXObjectRef *ref, NSDictionary *bindings) {
|
||||
static NSSet *ignored = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
ignored = [NSSet setWithArray:@[
|
||||
@"NSLayoutConstraint _container",
|
||||
@"NSContentSizeLayoutConstraint _container",
|
||||
@"NSAutoresizingMaskLayoutConstraint _container",
|
||||
@"MASViewConstraint _installedView",
|
||||
@"MASLayoutConstraint _container",
|
||||
@"MASViewAttribute _view"
|
||||
]];
|
||||
});
|
||||
|
||||
NSString *row = ref.reference;
|
||||
return ([row hasPrefix:@"NSLayout"] && [row hasSuffix:@" _referenceItem"]) ||
|
||||
([row hasPrefix:@"NSIS"] && [row hasSuffix:@" _delegate"]) ||
|
||||
([row hasPrefix:@"_NSAutoresizingMask"] && [row hasSuffix:@" _referenceItem"]) ||
|
||||
[ignored containsObject:row];
|
||||
};
|
||||
|
||||
BOOL(^isEssential)(FLEXObjectRef *, NSDictionary *) = ^BOOL(FLEXObjectRef *ref, NSDictionary *bindings) {
|
||||
return !(isObserver(ref, bindings) || isConstraintRelated(ref, bindings));
|
||||
};
|
||||
|
||||
switch (section) {
|
||||
case 0: return [NSPredicate predicateWithBlock:isEssential];
|
||||
case 1: return [NSPredicate predicateWithBlock:isConstraintRelated];
|
||||
case 2: return [NSPredicate predicateWithBlock:isObserver];
|
||||
|
||||
default: return nil;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSArray<NSPredicate *> *)defaultPredicates {
|
||||
return @[[self defaultPredicateForSection:0],
|
||||
[self defaultPredicateForSection:1],
|
||||
[self defaultPredicateForSection:2]];
|
||||
}
|
||||
|
||||
+ (NSArray<NSString *> *)defaultSectionTitles {
|
||||
return @[@"", @"AutoLayout", @"Trivial"];
|
||||
}
|
||||
|
||||
- (void)buildSections
|
||||
{
|
||||
NSInteger maxSections = self.maxSections;
|
||||
NSMutableArray *sections = [NSMutableArray array];
|
||||
for (NSInteger i = 0; i < maxSections; i++) {
|
||||
NSPredicate *predicate = self.predicates[i];
|
||||
[sections addObject:[self.instances filteredArrayUsingPredicate:predicate]];
|
||||
}
|
||||
|
||||
self.sections = sections;
|
||||
}
|
||||
|
||||
- (NSInteger)maxSections {
|
||||
return self.predicates.count ?: 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,12 +186,12 @@
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
return 1;
|
||||
return self.maxSections;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return [self.instances count];
|
||||
return self.sections[section].count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
@@ -99,26 +206,33 @@
|
||||
cell.detailTextLabel.font = cellFont;
|
||||
cell.detailTextLabel.textColor = [UIColor grayColor];
|
||||
}
|
||||
|
||||
id instance = self.instances[indexPath.row];
|
||||
NSString *title = nil;
|
||||
if ((NSInteger)[self.fieldNames count] > indexPath.row) {
|
||||
title = [NSString stringWithFormat:@"%@ %@", NSStringFromClass(object_getClass(instance)), self.fieldNames[indexPath.row]];
|
||||
} else {
|
||||
title = [NSString stringWithFormat:@"%@ %p", NSStringFromClass(object_getClass(instance)), instance];
|
||||
}
|
||||
cell.textLabel.text = title;
|
||||
cell.detailTextLabel.text = [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:instance];
|
||||
|
||||
FLEXObjectRef *row = self.sections[indexPath.section][indexPath.row];
|
||||
cell.textLabel.text = row.reference;
|
||||
cell.detailTextLabel.text = [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:row.object];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if (self.sectionTitles.count) {
|
||||
// Return nil instead of empty strings
|
||||
NSString *title = self.sectionTitles[section];
|
||||
if (title.length) {
|
||||
return title;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Table View Delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
id instance = self.instances[indexPath.row];
|
||||
id instance = self.instances[indexPath.row].object;
|
||||
FLEXObjectExplorerViewController *drillInViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:instance];
|
||||
[self.navigationController pushViewController:drillInViewController animated:YES];
|
||||
}
|
||||
|
||||
@@ -9,14 +9,16 @@
|
||||
#import "FLEXLibrariesTableViewController.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXClassesTableViewController.h"
|
||||
#import "FLEXClassExplorerViewController.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@interface FLEXLibrariesTableViewController () <UISearchBarDelegate>
|
||||
|
||||
@property (nonatomic, strong) NSArray *imageNames;
|
||||
@property (nonatomic, strong) NSArray *filteredImageNames;
|
||||
@property (nonatomic, strong) NSArray<NSString *> *imageNames;
|
||||
@property (nonatomic, strong) NSArray<NSString *> *filteredImageNames;
|
||||
|
||||
@property (nonatomic, strong) UISearchBar *searchBar;
|
||||
@property (nonatomic, strong) Class foundClass;
|
||||
|
||||
@end
|
||||
|
||||
@@ -50,7 +52,7 @@
|
||||
unsigned int imageNamesCount = 0;
|
||||
const char **imageNames = objc_copyImageNames(&imageNamesCount);
|
||||
if (imageNames) {
|
||||
NSMutableArray *imageNameStrings = [NSMutableArray array];
|
||||
NSMutableArray<NSString *> *imageNameStrings = [NSMutableArray array];
|
||||
NSString *appImageName = [FLEXUtility applicationImageName];
|
||||
for (unsigned int i = 0; i < imageNamesCount; i++) {
|
||||
const char *imageName = imageNames[i];
|
||||
@@ -63,9 +65,9 @@
|
||||
|
||||
// Sort alphabetically
|
||||
self.imageNames = [imageNameStrings sortedArrayWithOptions:0 usingComparator:^NSComparisonResult(NSString *name1, NSString *name2) {
|
||||
NSString *shortName1 = [self shortNameForImageName:name1];
|
||||
NSString *shortName2 = [self shortNameForImageName:name2];
|
||||
return [shortName1 caseInsensitiveCompare:shortName2];
|
||||
NSString *shortName1 = [self shortNameForImageName:name1];
|
||||
NSString *shortName2 = [self shortNameForImageName:name2];
|
||||
return [shortName1 caseInsensitiveCompare:shortName2];
|
||||
}];
|
||||
|
||||
free(imageNames);
|
||||
@@ -74,16 +76,14 @@
|
||||
|
||||
- (NSString *)shortNameForImageName:(NSString *)imageName
|
||||
{
|
||||
NSString *shortName = nil;
|
||||
NSArray *components = [imageName componentsSeparatedByString:@"/"];
|
||||
NSUInteger componentsCount = [components count];
|
||||
if (componentsCount >= 2) {
|
||||
shortName = [NSString stringWithFormat:@"%@/%@", components[componentsCount - 2], components[componentsCount - 1]];
|
||||
NSArray<NSString *> *components = [imageName componentsSeparatedByString:@"/"];
|
||||
if (components.count >= 2) {
|
||||
return [NSString stringWithFormat:@"%@/%@", components[components.count - 2], components[components.count - 1]];
|
||||
}
|
||||
return shortName;
|
||||
return imageName.lastPathComponent;
|
||||
}
|
||||
|
||||
- (void)setImageNames:(NSArray *)imageNames
|
||||
- (void)setImageNames:(NSArray<NSString *> *)imageNames
|
||||
{
|
||||
if (![_imageNames isEqual:imageNames]) {
|
||||
_imageNames = imageNames;
|
||||
@@ -97,7 +97,7 @@
|
||||
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
|
||||
{
|
||||
if ([searchText length] > 0) {
|
||||
NSPredicate *searchPreidcate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
|
||||
NSPredicate *searchPreidcate = [NSPredicate predicateWithBlock:^BOOL(NSString *evaluatedObject, NSDictionary<NSString *, id> *bindings) {
|
||||
BOOL matches = NO;
|
||||
NSString *shortName = [self shortNameForImageName:evaluatedObject];
|
||||
if ([shortName rangeOfString:searchText options:NSCaseInsensitiveSearch].length > 0) {
|
||||
@@ -109,6 +109,8 @@
|
||||
} else {
|
||||
self.filteredImageNames = self.imageNames;
|
||||
}
|
||||
|
||||
self.foundClass = NSClassFromString(searchText);
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
@@ -127,22 +129,32 @@
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return [self.filteredImageNames count];
|
||||
return self.filteredImageNames.count + (self.foundClass ? 1 : 0);
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
static NSString *CellIdentifier = @"Cell";
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
|
||||
static NSString *cellIdentifier = @"Cell";
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
|
||||
if (!cell) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
cell.textLabel.font = [FLEXUtility defaultTableViewCellLabelFont];
|
||||
}
|
||||
|
||||
NSString *fullImageName = self.filteredImageNames[indexPath.row];
|
||||
cell.textLabel.text = [self shortNameForImageName:fullImageName];
|
||||
NSString *executablePath;
|
||||
if (self.foundClass) {
|
||||
if (indexPath.row == 0) {
|
||||
cell.textLabel.text = [NSString stringWithFormat:@"Class \"%@\"", self.searchBar.text];
|
||||
return cell;
|
||||
} else {
|
||||
executablePath = self.filteredImageNames[indexPath.row-1];
|
||||
}
|
||||
} else {
|
||||
executablePath = self.filteredImageNames[indexPath.row];
|
||||
}
|
||||
|
||||
cell.textLabel.text = [self shortNameForImageName:executablePath];
|
||||
return cell;
|
||||
}
|
||||
|
||||
@@ -151,9 +163,15 @@
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
FLEXClassesTableViewController *classesViewController = [[FLEXClassesTableViewController alloc] init];
|
||||
classesViewController.binaryImageName = self.filteredImageNames[indexPath.row];
|
||||
[self.navigationController pushViewController:classesViewController animated:YES];
|
||||
if (indexPath.row == 0 && self.foundClass) {
|
||||
FLEXClassExplorerViewController *objectExplorer = [FLEXClassExplorerViewController new];
|
||||
objectExplorer.object = self.foundClass;
|
||||
[self.navigationController pushViewController:objectExplorer animated:YES];
|
||||
} else {
|
||||
FLEXClassesTableViewController *classesViewController = [[FLEXClassesTableViewController alloc] init];
|
||||
classesViewController.binaryImageName = self.filteredImageNames[self.foundClass ? indexPath.row-1 : indexPath.row];
|
||||
[self.navigationController pushViewController:classesViewController animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -14,12 +14,14 @@
|
||||
|
||||
static const NSInteger kFLEXLiveObjectsSortAlphabeticallyIndex = 0;
|
||||
static const NSInteger kFLEXLiveObjectsSortByCountIndex = 1;
|
||||
static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
|
||||
|
||||
@interface FLEXLiveObjectsTableViewController () <UISearchBarDelegate>
|
||||
|
||||
@property (nonatomic, strong) NSDictionary *instanceCountsForClassNames;
|
||||
@property (nonatomic, readonly) NSArray *allClassNames;
|
||||
@property (nonatomic, strong) NSArray *filteredClassNames;
|
||||
@property (nonatomic, strong) NSDictionary<NSString *, NSNumber *> *instanceCountsForClassNames;
|
||||
@property (nonatomic, strong) NSDictionary<NSString *, NSNumber *> *instanceSizesForClassNames;
|
||||
@property (nonatomic, readonly) NSArray<NSString *> *allClassNames;
|
||||
@property (nonatomic, strong) NSArray<NSString *> *filteredClassNames;
|
||||
@property (nonatomic, strong) UISearchBar *searchBar;
|
||||
|
||||
@end
|
||||
@@ -34,7 +36,7 @@ static const NSInteger kFLEXLiveObjectsSortByCountIndex = 1;
|
||||
self.searchBar.placeholder = [FLEXUtility searchBarPlaceholderText];
|
||||
self.searchBar.delegate = self;
|
||||
self.searchBar.showsScopeBar = YES;
|
||||
self.searchBar.scopeButtonTitles = @[@"Sort Alphabetically", @"Sort by Count"];
|
||||
self.searchBar.scopeButtonTitles = @[@"Sort Alphabetically", @"Sort by Count", @"Sort by Size"];
|
||||
[self.searchBar sizeToFit];
|
||||
self.tableView.tableHeaderView = self.searchBar;
|
||||
|
||||
@@ -44,7 +46,7 @@ static const NSInteger kFLEXLiveObjectsSortByCountIndex = 1;
|
||||
[self reloadTableData];
|
||||
}
|
||||
|
||||
- (NSArray *)allClassNames
|
||||
- (NSArray<NSString *> *)allClassNames
|
||||
{
|
||||
return [self.instanceCountsForClassNames allKeys];
|
||||
}
|
||||
@@ -72,18 +74,21 @@ static const NSInteger kFLEXLiveObjectsSortByCountIndex = 1;
|
||||
}];
|
||||
|
||||
// Convert our CF primitive dictionary into a nicer mapping of class name strings to counts that we will use as the table's model.
|
||||
NSMutableDictionary *mutableCountsForClassNames = [NSMutableDictionary dictionary];
|
||||
NSMutableDictionary<NSString *, NSNumber *> *mutableCountsForClassNames = [NSMutableDictionary dictionary];
|
||||
NSMutableDictionary<NSString *, NSNumber *> *mutableSizesForClassNames = [NSMutableDictionary dictionary];
|
||||
for (unsigned int i = 0; i < classCount; i++) {
|
||||
Class class = classes[i];
|
||||
NSUInteger instanceCount = (NSUInteger)CFDictionaryGetValue(mutableCountsForClasses, (__bridge const void *)(class));
|
||||
NSString *className = @(class_getName(class));
|
||||
if (instanceCount > 0) {
|
||||
NSString *className = @(class_getName(class));
|
||||
[mutableCountsForClassNames setObject:@(instanceCount) forKey:className];
|
||||
}
|
||||
[mutableSizesForClassNames setObject:@(class_getInstanceSize(class)) forKey:className];
|
||||
}
|
||||
free(classes);
|
||||
|
||||
self.instanceCountsForClassNames = mutableCountsForClassNames;
|
||||
self.instanceSizesForClassNames = mutableSizesForClassNames;
|
||||
|
||||
[self updateTableDataForSearchFilter];
|
||||
}
|
||||
@@ -99,19 +104,27 @@ static const NSInteger kFLEXLiveObjectsSortByCountIndex = 1;
|
||||
NSString *title = @"Live Objects";
|
||||
|
||||
NSUInteger totalCount = 0;
|
||||
NSUInteger totalSize = 0;
|
||||
for (NSString *className in self.allClassNames) {
|
||||
totalCount += [self.instanceCountsForClassNames[className] unsignedIntegerValue];
|
||||
NSUInteger count = [self.instanceCountsForClassNames[className] unsignedIntegerValue];
|
||||
totalCount += count;
|
||||
totalSize += count * [self.instanceSizesForClassNames[className] unsignedIntegerValue];
|
||||
}
|
||||
NSUInteger filteredCount = 0;
|
||||
NSUInteger filteredSize = 0;
|
||||
for (NSString *className in self.filteredClassNames) {
|
||||
filteredCount += [self.instanceCountsForClassNames[className] unsignedIntegerValue];
|
||||
NSUInteger count = [self.instanceCountsForClassNames[className] unsignedIntegerValue];
|
||||
filteredCount += count;
|
||||
filteredSize += count * [self.instanceSizesForClassNames[className] unsignedIntegerValue];
|
||||
}
|
||||
|
||||
if (filteredCount == totalCount) {
|
||||
// Unfiltered
|
||||
title = [title stringByAppendingFormat:@" (%lu)", (unsigned long)totalCount];
|
||||
title = [title stringByAppendingFormat:@" (%lu, %@)", (unsigned long)totalCount,
|
||||
[NSByteCountFormatter stringFromByteCount:totalSize countStyle:NSByteCountFormatterCountStyleFile]];
|
||||
} else {
|
||||
title = [title stringByAppendingFormat:@" (filtered, %lu)", (unsigned long)filteredCount];
|
||||
title = [title stringByAppendingFormat:@" (filtered, %lu, %@)", (unsigned long)filteredCount,
|
||||
[NSByteCountFormatter stringFromByteCount:filteredSize countStyle:NSByteCountFormatterCountStyleFile]];
|
||||
}
|
||||
|
||||
self.title = title;
|
||||
@@ -159,6 +172,15 @@ static const NSInteger kFLEXLiveObjectsSortByCountIndex = 1;
|
||||
// Reversed for descending counts.
|
||||
return [count2 compare:count1];
|
||||
}];
|
||||
} else if (self.searchBar.selectedScopeButtonIndex == kFLEXLiveObjectsSortBySizeIndex) {
|
||||
self.filteredClassNames = [self.filteredClassNames sortedArrayUsingComparator:^NSComparisonResult(NSString *className1, NSString *className2) {
|
||||
NSNumber *count1 = self.instanceCountsForClassNames[className1];
|
||||
NSNumber *count2 = self.instanceCountsForClassNames[className2];
|
||||
NSNumber *size1 = self.instanceSizesForClassNames[className1];
|
||||
NSNumber *size2 = self.instanceSizesForClassNames[className2];
|
||||
// Reversed for descending sizes.
|
||||
return [@(count2.integerValue * size2.integerValue) compare:@(count1.integerValue * size1.integerValue)];
|
||||
}];
|
||||
}
|
||||
|
||||
[self updateTitle];
|
||||
@@ -190,7 +212,10 @@ static const NSInteger kFLEXLiveObjectsSortByCountIndex = 1;
|
||||
|
||||
NSString *className = self.filteredClassNames[indexPath.row];
|
||||
NSNumber *count = self.instanceCountsForClassNames[className];
|
||||
cell.textLabel.text = [NSString stringWithFormat:@"%@ (%ld)", className, (long)[count integerValue]];
|
||||
NSNumber *size = self.instanceSizesForClassNames[className];
|
||||
unsigned long totalSize = count.unsignedIntegerValue * size.unsignedIntegerValue;
|
||||
cell.textLabel.text = [NSString stringWithFormat:@"%@ (%ld, %@)", className, (long)[count integerValue],
|
||||
[NSByteCountFormatter stringFromByteCount:totalSize countStyle:NSByteCountFormatterCountStyleFile]];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// FLEXObjectRef.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner Bennett on 7/24/18.
|
||||
// Copyright (c) 2018 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface FLEXObjectRef : NSObject
|
||||
|
||||
+ (instancetype)referencing:(id)object;
|
||||
+ (instancetype)referencing:(id)object ivar:(NSString *)ivarName;
|
||||
|
||||
+ (NSArray<FLEXObjectRef *> *)referencingAll:(NSArray *)objects;
|
||||
|
||||
/// For example, "NSString 0x1d4085d0" or "NSLayoutConstraint _object"
|
||||
@property (nonatomic, readonly) NSString *reference;
|
||||
@property (nonatomic, readonly) id object;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// FLEXObjectRef.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner Bennett on 7/24/18.
|
||||
// Copyright (c) 2018 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXObjectRef.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation FLEXObjectRef
|
||||
|
||||
+ (instancetype)referencing:(id)object {
|
||||
return [[self alloc] initWithObject:object ivarName:nil];
|
||||
}
|
||||
|
||||
+ (instancetype)referencing:(id)object ivar:(NSString *)ivarName {
|
||||
return [[self alloc] initWithObject:object ivarName:ivarName];
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXObjectRef *> *)referencingAll:(NSArray *)objects {
|
||||
NSMutableArray<FLEXObjectRef *> *refs = [NSMutableArray array];
|
||||
for (id obj in objects) {
|
||||
[refs addObject:[self referencing:obj]];
|
||||
}
|
||||
|
||||
return refs;
|
||||
}
|
||||
|
||||
- (id)initWithObject:(id)object ivarName:(NSString *)ivar {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_object = object;
|
||||
|
||||
NSString *class = NSStringFromClass(object_getClass(object));
|
||||
if (ivar) {
|
||||
_reference = [NSString stringWithFormat:@"%@ %@", class, ivar];
|
||||
} else {
|
||||
_reference = [NSString stringWithFormat:@"%@ %p", class, object];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -102,23 +102,23 @@
|
||||
+ (BOOL)supportsPathExtension:(NSString *)extension
|
||||
{
|
||||
BOOL supported = NO;
|
||||
NSSet *supportedExtensions = [self webViewSupportedPathExtensions];
|
||||
NSSet<NSString *> *supportedExtensions = [self webViewSupportedPathExtensions];
|
||||
if ([supportedExtensions containsObject:[extension lowercaseString]]) {
|
||||
supported = YES;
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
+ (NSSet *)webViewSupportedPathExtensions
|
||||
+ (NSSet<NSString *> *)webViewSupportedPathExtensions
|
||||
{
|
||||
static NSSet *pathExtenstions = nil;
|
||||
static NSSet<NSString *> *pathExtenstions = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
// Note that this is not exhaustive, but all these extensions should work well in the web view.
|
||||
// See https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/CreatingContentforSafarioniPhone/CreatingContentforSafarioniPhone.html#//apple_ref/doc/uid/TP40006482-SW7
|
||||
pathExtenstions = [NSSet setWithArray:@[@"jpg", @"jpeg", @"png", @"gif", @"pdf", @"svg", @"tiff", @"3gp", @"3gpp", @"3g2",
|
||||
@"3gp2", @"aiff", @"aif", @"aifc", @"cdda", @"amr", @"mp3", @"swa", @"mp4", @"mpeg",
|
||||
@"mpg", @"mp3", @"wav", @"bwf", @"m4a", @"m4b", @"m4p", @"mov", @"qt", @"mqv", @"m4v"]];
|
||||
pathExtenstions = [NSSet<NSString *> setWithArray:@[@"jpg", @"jpeg", @"png", @"gif", @"pdf", @"svg", @"tiff", @"3gp", @"3gpp", @"3g2",
|
||||
@"3gp2", @"aiff", @"aif", @"aifc", @"cdda", @"amr", @"mp3", @"swa", @"mp4", @"mpeg",
|
||||
@"mpg", @"mp3", @"wav", @"bwf", @"m4a", @"m4b", @"m4p", @"mov", @"qt", @"mqv", @"m4v"]];
|
||||
|
||||
});
|
||||
return pathExtenstions;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
@implementation FLEXSystemLogMessage
|
||||
|
||||
+(instancetype)logMessageFromASLMessage:(aslmsg)aslMessage
|
||||
+ (instancetype)logMessageFromASLMessage:(aslmsg)aslMessage
|
||||
{
|
||||
FLEXSystemLogMessage *logMessage = [[FLEXSystemLogMessage alloc] init];
|
||||
|
||||
|
||||
@@ -74,12 +74,12 @@ static const UIEdgeInsets kFLEXLogMessageCellInsets = {10.0, 10.0, 10.0, 10.0};
|
||||
+ (NSAttributedString *)attributedTextForLogMessage:(FLEXSystemLogMessage *)logMessage highlightedText:(NSString *)highlightedText
|
||||
{
|
||||
NSString *text = [self displayedTextForLogMessage:logMessage];
|
||||
NSDictionary *attributes = @{ NSFontAttributeName : [UIFont fontWithName:@"CourierNewPSMT" size:12.0] };
|
||||
NSDictionary<NSString *, id> *attributes = @{ NSFontAttributeName : [UIFont fontWithName:@"CourierNewPSMT" size:12.0] };
|
||||
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:attributes];
|
||||
|
||||
if ([highlightedText length] > 0) {
|
||||
NSMutableAttributedString *mutableAttributedText = [attributedText mutableCopy];
|
||||
NSMutableDictionary *highlightAttributes = [@{ NSBackgroundColorAttributeName : [UIColor yellowColor] } mutableCopy];
|
||||
NSMutableDictionary<NSString *, id> *highlightAttributes = [@{ NSBackgroundColorAttributeName : [UIColor yellowColor] } mutableCopy];
|
||||
[highlightAttributes addEntriesFromDictionary:attributes];
|
||||
|
||||
NSRange remainingSearchRange = NSMakeRange(0, text.length);
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
@interface FLEXSystemLogTableViewController () <UISearchResultsUpdating, UISearchControllerDelegate>
|
||||
|
||||
@property (nonatomic, strong) UISearchController *searchController;
|
||||
@property (nonatomic, copy) NSArray *logMessages;
|
||||
@property (nonatomic, copy) NSArray *filteredLogMessages;
|
||||
@property (nonatomic, readonly) NSMutableArray<FLEXSystemLogMessage *> *logMessages;
|
||||
@property (nonatomic, copy) NSArray<FLEXSystemLogMessage *> *filteredLogMessages;
|
||||
@property (nonatomic, strong) NSTimer *logUpdateTimer;
|
||||
@property (nonatomic, readonly) NSMutableIndexSet *logMessageIdentifiers;
|
||||
|
||||
@end
|
||||
|
||||
@@ -27,6 +28,9 @@
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
_logMessages = [NSMutableArray array];
|
||||
_logMessageIdentifiers = [NSMutableIndexSet indexSet];
|
||||
|
||||
[self.tableView registerClass:[FLEXSystemLogTableViewCell class] forCellReuseIdentifier:kFLEXSystemLogTableViewCellIdentifier];
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
self.title = @"Loading...";
|
||||
@@ -65,10 +69,18 @@
|
||||
- (void)updateLogMessages
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSArray *logMessages = [[self class] allLogMessagesForCurrentProcess];
|
||||
NSArray<FLEXSystemLogMessage *> *newMessages = [self newLogMessagesForCurrentProcess];
|
||||
if (!newMessages.count) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.title = @"System Log";
|
||||
self.logMessages = logMessages;
|
||||
|
||||
[self.logMessages addObjectsFromArray:newMessages];
|
||||
for (FLEXSystemLogMessage *message in newMessages) {
|
||||
[self.logMessageIdentifiers addIndex:(NSUInteger)message.messageID];
|
||||
}
|
||||
|
||||
// "Follow" the log as new messages stream in if we were previously near the bottom.
|
||||
BOOL wasNearBottom = self.tableView.contentOffset.y >= self.tableView.contentSize.height - self.tableView.frame.size.height - 100.0;
|
||||
@@ -154,7 +166,7 @@
|
||||
{
|
||||
NSString *searchString = searchController.searchBar.text;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSArray *filteredLogMessages = [self.logMessages filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(FLEXSystemLogMessage *logMessage, NSDictionary *bindings) {
|
||||
NSArray<FLEXSystemLogMessage *> *filteredLogMessages = [self.logMessages filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(FLEXSystemLogMessage *logMessage, NSDictionary<NSString *, id> *bindings) {
|
||||
NSString *displayedText = [FLEXSystemLogTableViewCell displayedTextForLogMessage:logMessage];
|
||||
return [displayedText rangeOfString:searchString options:NSCaseInsensitiveSearch].length > 0;
|
||||
}]];
|
||||
@@ -169,40 +181,56 @@
|
||||
|
||||
#pragma mark - Log Message Fetching
|
||||
|
||||
// Due to a mistake in asl.h, things get a little messy. We need to mark these symbols as weak since they won't exist on iOS 7 despite the compiler thinking otherwise.
|
||||
// asl.h in the iOS 8.1 SDK claims that asl_next() and asl_release() were introduced in iOS 7 to replace aslresponse_next() and aslresponse_free(). However, they were actually added in iOS 8.0.
|
||||
extern aslmsg asl_next(asl_object_t obj) __attribute__((weak_import));
|
||||
extern void asl_release(asl_object_t obj) __attribute__((weak_import));
|
||||
|
||||
+ (NSArray *)allLogMessagesForCurrentProcess
|
||||
- (NSArray<FLEXSystemLogMessage *> *)newLogMessagesForCurrentProcess
|
||||
{
|
||||
asl_object_t query = asl_new(ASL_TYPE_QUERY);
|
||||
if (!self.logMessages.count) {
|
||||
return [[self class] allLogMessagesForCurrentProcess];
|
||||
}
|
||||
|
||||
// Filter for messages from the current process. Note that this appears to happen by default on device, but is required in the simulator.
|
||||
NSString *pidString = [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]];
|
||||
asl_set_query(query, ASL_KEY_PID, [pidString UTF8String], ASL_QUERY_OP_EQUAL);
|
||||
|
||||
aslresponse response = asl_search(NULL, query);
|
||||
aslresponse response = [FLEXSystemLogTableViewController ASLMessageListForCurrentProcess];
|
||||
aslmsg aslMessage = NULL;
|
||||
|
||||
NSMutableArray *logMessages = [NSMutableArray array];
|
||||
NSMutableArray<FLEXSystemLogMessage *> *newMessages = [NSMutableArray array];
|
||||
|
||||
if (&asl_next != NULL && &asl_release != NULL) {
|
||||
while ((aslMessage = asl_next(response))) {
|
||||
[logMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
||||
while ((aslMessage = asl_next(response))) {
|
||||
NSUInteger messageID = (NSUInteger)atoll(asl_get(aslMessage, ASL_KEY_MSG_ID));
|
||||
if (![self.logMessageIdentifiers containsIndex:messageID]) {
|
||||
[newMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
||||
}
|
||||
asl_release(response);
|
||||
} else {
|
||||
// Mute incorrect deprecated warnings. We'll need the "deprecated" functions on iOS 7, where their replacements don't yet exist.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
while ((aslMessage = aslresponse_next(response))) {
|
||||
[logMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
||||
}
|
||||
aslresponse_free(response);
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
asl_release(response);
|
||||
return newMessages;
|
||||
}
|
||||
|
||||
+ (aslresponse)ASLMessageListForCurrentProcess
|
||||
{
|
||||
static NSString *pidString = nil;
|
||||
if (!pidString) {
|
||||
pidString = @([[NSProcessInfo processInfo] processIdentifier]).stringValue;
|
||||
}
|
||||
|
||||
// Create system log query object.
|
||||
asl_object_t query = asl_new(ASL_TYPE_QUERY);
|
||||
|
||||
// Filter for messages from the current process.
|
||||
// Note that this appears to happen by default on device, but is required in the simulator.
|
||||
asl_set_query(query, ASL_KEY_PID, pidString.UTF8String, ASL_QUERY_OP_EQUAL);
|
||||
|
||||
return asl_search(NULL, query);
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXSystemLogMessage *> *)allLogMessagesForCurrentProcess
|
||||
{
|
||||
aslresponse response = [self ASLMessageListForCurrentProcess];
|
||||
aslmsg aslMessage = NULL;
|
||||
|
||||
NSMutableArray<FLEXSystemLogMessage *> *logMessages = [NSMutableArray array];
|
||||
while ((aslMessage = asl_next(response))) {
|
||||
[logMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
||||
}
|
||||
asl_release(response);
|
||||
|
||||
return logMessages;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -8,9 +8,11 @@
|
||||
|
||||
#import "FLEXManager.h"
|
||||
|
||||
@class FLEXGlobalsTableViewControllerEntry;
|
||||
|
||||
@interface FLEXManager ()
|
||||
|
||||
/// An array of FLEXGlobalsTableViewControllerEntry objects that have been registered by the user.
|
||||
@property (nonatomic, readonly, strong) NSArray *userGlobalEntries;
|
||||
@property (nonatomic, readonly, strong) NSArray<FLEXGlobalsTableViewControllerEntry *> *userGlobalEntries;
|
||||
|
||||
@end
|
||||
@@ -24,7 +24,7 @@
|
||||
@property (nonatomic, strong) FLEXWindow *explorerWindow;
|
||||
@property (nonatomic, strong) FLEXExplorerViewController *explorerViewController;
|
||||
|
||||
@property (nonatomic, readonly, strong) NSMutableArray *userGlobalEntries;
|
||||
@property (nonatomic, readonly, strong) NSMutableArray<FLEXGlobalsTableViewControllerEntry *> *userGlobalEntries;
|
||||
|
||||
@end
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_userGlobalEntries = [[NSMutableArray alloc] init];
|
||||
_userGlobalEntries = [NSMutableArray array];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -115,6 +115,16 @@
|
||||
[[FLEXNetworkRecorder defaultRecorder] setResponseCacheByteLimit:networkResponseCacheByteLimit];
|
||||
}
|
||||
|
||||
- (void)setNetworkRequestHostBlacklist:(NSArray<NSString *> *)networkRequestHostBlacklist
|
||||
{
|
||||
[FLEXNetworkRecorder defaultRecorder].hostBlacklist = networkRequestHostBlacklist;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)hostBlacklist
|
||||
{
|
||||
return [FLEXNetworkRecorder defaultRecorder].hostBlacklist;
|
||||
}
|
||||
|
||||
#pragma mark - FLEXWindowEventDelegate
|
||||
|
||||
- (BOOL)shouldHandleTouchAtPoint:(CGPoint)pointInWindow
|
||||
@@ -302,7 +312,7 @@
|
||||
|
||||
- (UIScrollView *)firstScrollView
|
||||
{
|
||||
NSMutableArray *views = [[[[UIApplication sharedApplication] keyWindow] subviews] mutableCopy];
|
||||
NSMutableArray<UIView *> *views = [[[[UIApplication sharedApplication] keyWindow] subviews] mutableCopy];
|
||||
UIScrollView *scrollView = nil;
|
||||
while ([views count] > 0) {
|
||||
UIView *view = [views firstObject];
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// FLEXCurlLogger.h
|
||||
//
|
||||
//
|
||||
// Created by Ji Pei on 07/27/16
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface FLEXNetworkCurlLogger : NSObject
|
||||
|
||||
/**
|
||||
* Generates a cURL command equivalent to the given request.
|
||||
*
|
||||
* @param request The request to be translated
|
||||
*/
|
||||
+ (NSString *)curlCommandString:(NSURLRequest *)request;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// FLEXCurlLogger.m
|
||||
//
|
||||
//
|
||||
// Created by Ji Pei on 07/27/16
|
||||
//
|
||||
|
||||
#import "FLEXNetworkCurlLogger.h"
|
||||
|
||||
@implementation FLEXNetworkCurlLogger
|
||||
|
||||
+ (NSString *)curlCommandString:(NSURLRequest *)request {
|
||||
__block NSMutableString *curlCommandString = [NSMutableString stringWithFormat:@"curl -v -X %@ ", request.HTTPMethod];
|
||||
|
||||
[curlCommandString appendFormat:@"\'%@\' ", request.URL.absoluteString];
|
||||
|
||||
[request.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *val, BOOL *stop) {
|
||||
[curlCommandString appendFormat:@"-H \'%@: %@\' ", key, val];
|
||||
}];
|
||||
|
||||
NSArray<NSHTTPCookie *> *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:request.URL];
|
||||
if (cookies) {
|
||||
[curlCommandString appendFormat:@"-H \'Cookie:"];
|
||||
for (NSHTTPCookie *cookie in cookies) {
|
||||
[curlCommandString appendFormat:@" %@=%@;", cookie.name, cookie.value];
|
||||
}
|
||||
[curlCommandString appendFormat:@"\' "];
|
||||
}
|
||||
|
||||
if (request.HTTPBody) {
|
||||
if ([request.allHTTPHeaderFields[@"Content-Length"] intValue] < 1024) {
|
||||
[curlCommandString appendFormat:@"-d \'%@\'",
|
||||
[[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding]];
|
||||
} else {
|
||||
[curlCommandString appendFormat:@"[TOO MUCH DATA TO INCLUDE]"];
|
||||
}
|
||||
}
|
||||
|
||||
return curlCommandString;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -17,9 +17,9 @@
|
||||
@interface FLEXNetworkHistoryTableViewController () <UISearchResultsUpdating, UISearchControllerDelegate>
|
||||
|
||||
/// Backing model
|
||||
@property (nonatomic, copy) NSArray *networkTransactions;
|
||||
@property (nonatomic, copy) NSArray<FLEXNetworkTransaction *> *networkTransactions;
|
||||
@property (nonatomic, assign) long long bytesReceived;
|
||||
@property (nonatomic, copy) NSArray *filteredNetworkTransactions;
|
||||
@property (nonatomic, copy) NSArray<FLEXNetworkTransaction *> *filteredNetworkTransactions;
|
||||
@property (nonatomic, assign) long long filteredBytesReceived;
|
||||
|
||||
@property (nonatomic, assign) BOOL rowInsertInProgress;
|
||||
@@ -41,6 +41,10 @@
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNetworkObserverEnabledStateChangedNotification:) name:kFLEXNetworkObserverEnabledStateChangedNotification object:nil];
|
||||
self.title = @"📡 Network";
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Settings" style:UIBarButtonItemStylePlain target:self action:@selector(settingsButtonTapped:)];
|
||||
|
||||
// Needed to avoid search bar showing over detail pages pushed on the nav stack
|
||||
// see http://asciiwwdc.com/2014/sessions/228
|
||||
self.definesPresentationContext = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -86,7 +90,7 @@
|
||||
self.networkTransactions = [[FLEXNetworkRecorder defaultRecorder] networkTransactions];
|
||||
}
|
||||
|
||||
- (void)setNetworkTransactions:(NSArray *)networkTransactions
|
||||
- (void)setNetworkTransactions:(NSArray<FLEXNetworkTransaction *> *)networkTransactions
|
||||
{
|
||||
if (![_networkTransactions isEqual:networkTransactions]) {
|
||||
_networkTransactions = networkTransactions;
|
||||
@@ -105,7 +109,7 @@
|
||||
[self updateFirstSectionHeader];
|
||||
}
|
||||
|
||||
- (void)setFilteredNetworkTransactions:(NSArray *)filteredNetworkTransactions
|
||||
- (void)setFilteredNetworkTransactions:(NSArray<FLEXNetworkTransaction *> *)filteredNetworkTransactions
|
||||
{
|
||||
if (![_filteredNetworkTransactions isEqual:filteredNetworkTransactions]) {
|
||||
_filteredNetworkTransactions = filteredNetworkTransactions;
|
||||
@@ -192,7 +196,7 @@
|
||||
[self tryUpdateTransactions];
|
||||
}];
|
||||
|
||||
NSMutableArray *indexPathsToReload = [NSMutableArray array];
|
||||
NSMutableArray<NSIndexPath *> *indexPathsToReload = [NSMutableArray array];
|
||||
for (NSInteger row = 0; row < addedRowCount; row++) {
|
||||
[indexPathsToReload addObject:[NSIndexPath indexPathForRow:row inSection:0]];
|
||||
}
|
||||
@@ -328,7 +332,7 @@
|
||||
{
|
||||
NSString *searchString = self.searchController.searchBar.text;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSArray *filteredNetworkTransactions = [self.networkTransactions filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(FLEXNetworkTransaction *transaction, NSDictionary *bindings) {
|
||||
NSArray<FLEXNetworkTransaction *> *filteredNetworkTransactions = [self.networkTransactions filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(FLEXNetworkTransaction *transaction, NSDictionary<NSString *, id> *bindings) {
|
||||
return [[transaction.request.URL absoluteString] rangeOfString:searchString options:NSCaseInsensitiveSearch].length > 0;
|
||||
}]];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
@@ -27,10 +27,13 @@ extern NSString *const kFLEXNetworkRecorderTransactionsClearedNotification;
|
||||
/// If NO, the recorder not cache will not cache response for content types with an "image", "video", or "audio" prefix.
|
||||
@property (nonatomic, assign) BOOL shouldCacheMediaResponses;
|
||||
|
||||
@property (nonatomic, copy) NSArray<NSString *> *hostBlacklist;
|
||||
|
||||
|
||||
// Accessing recorded network activity
|
||||
|
||||
/// Array of FLEXNetworkTransaction objects ordered by start time with the newest first.
|
||||
- (NSArray *)networkTransactions;
|
||||
- (NSArray<FLEXNetworkTransaction *> *)networkTransactions;
|
||||
|
||||
/// The full response data IFF it hasn't been purged due to memory pressure.
|
||||
- (NSData *)cachedResponseBodyForTransaction:(FLEXNetworkTransaction *)transaction;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import "FLEXNetworkRecorder.h"
|
||||
#import "FLEXNetworkCurlLogger.h"
|
||||
#import "FLEXNetworkTransaction.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXResources.h"
|
||||
@@ -21,8 +22,8 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
|
||||
@interface FLEXNetworkRecorder ()
|
||||
|
||||
@property (nonatomic, strong) NSCache *responseCache;
|
||||
@property (nonatomic, strong) NSMutableArray *orderedTransactions;
|
||||
@property (nonatomic, strong) NSMutableDictionary *networkTransactionsForRequestIdentifiers;
|
||||
@property (nonatomic, strong) NSMutableArray<FLEXNetworkTransaction *> *orderedTransactions;
|
||||
@property (nonatomic, strong) NSMutableDictionary<NSString *, FLEXNetworkTransaction *> *networkTransactionsForRequestIdentifiers;
|
||||
@property (nonatomic, strong) dispatch_queue_t queue;
|
||||
|
||||
@end
|
||||
@@ -73,9 +74,9 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@(responseCacheByteLimit) forKey:kFLEXNetworkRecorderResponseCacheLimitDefaultsKey];
|
||||
}
|
||||
|
||||
- (NSArray *)networkTransactions
|
||||
- (NSArray<FLEXNetworkTransaction *> *)networkTransactions
|
||||
{
|
||||
__block NSArray *transactions = nil;
|
||||
__block NSArray<FLEXNetworkTransaction *> *transactions = nil;
|
||||
dispatch_sync(self.queue, ^{
|
||||
transactions = [self.orderedTransactions copy];
|
||||
});
|
||||
@@ -103,6 +104,12 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
|
||||
|
||||
- (void)recordRequestWillBeSentWithRequestID:(NSString *)requestID request:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
|
||||
{
|
||||
for (NSString *host in self.hostBlacklist) {
|
||||
if ([request.URL.host hasSuffix:host]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NSDate *startDate = [NSDate date];
|
||||
|
||||
if (redirectResponse) {
|
||||
@@ -168,7 +175,7 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
|
||||
|
||||
BOOL shouldCache = [responseBody length] > 0;
|
||||
if (!self.shouldCacheMediaResponses) {
|
||||
NSArray *ignoredMIMETypePrefixes = @[ @"audio", @"image", @"video" ];
|
||||
NSArray<NSString *> *ignoredMIMETypePrefixes = @[ @"audio", @"image", @"video" ];
|
||||
for (NSString *ignoredPrefix in ignoredMIMETypePrefixes) {
|
||||
shouldCache = shouldCache && ![transaction.response.MIMEType hasPrefix:ignoredPrefix];
|
||||
}
|
||||
@@ -245,7 +252,7 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
|
||||
- (void)postNewTransactionNotificationWithTransaction:(FLEXNetworkTransaction *)transaction
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSDictionary *userInfo = @{ kFLEXNetworkRecorderUserInfoTransactionKey : transaction };
|
||||
NSDictionary<NSString *, id> *userInfo = @{ kFLEXNetworkRecorderUserInfoTransactionKey : transaction };
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kFLEXNetworkRecorderNewTransactionNotification object:self userInfo:userInfo];
|
||||
});
|
||||
}
|
||||
@@ -253,7 +260,7 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
|
||||
- (void)postUpdateNotificationForTransaction:(FLEXNetworkTransaction *)transaction
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSDictionary *userInfo = @{ kFLEXNetworkRecorderUserInfoTransactionKey : transaction };
|
||||
NSDictionary<NSString *, id> *userInfo = @{ kFLEXNetworkRecorderUserInfoTransactionKey : transaction };
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kFLEXNetworkRecorderTransactionUpdatedNotification object:self userInfo:userInfo];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
@interface FLEXNetworkSettingsTableViewController () <UIActionSheetDelegate>
|
||||
|
||||
@property (nonatomic, copy) NSArray *cells;
|
||||
@property (nonatomic, copy) NSArray<UITableViewCell *> *cells;
|
||||
|
||||
@property (nonatomic, strong) UITableViewCell *cacheLimitCell;
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
NSMutableArray *mutableCells = [NSMutableArray array];
|
||||
NSMutableArray<UITableViewCell *> *mutableCells = [NSMutableArray array];
|
||||
|
||||
UITableViewCell *networkDebuggingCell = [self switchCellWithTitle:@"Network Debugging" toggleAction:@selector(networkDebuggingToggled:) isOn:[FLEXNetworkObserver isEnabled]];
|
||||
[mutableCells addObject:networkDebuggingCell];
|
||||
@@ -136,7 +136,7 @@
|
||||
if (isDestructive) {
|
||||
actionButton.tintColor = [UIColor redColor];
|
||||
}
|
||||
actionButton.titleLabel.font = [[self class] cellTitleFont];;
|
||||
actionButton.titleLabel.font = [[self class] cellTitleFont];
|
||||
[actionButton addTarget:self action:@selector(clearRequestsTapped:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
[buttonCell.contentView addSubview:actionButton];
|
||||
|
||||
@@ -36,6 +36,9 @@ typedef NS_ENUM(NSInteger, FLEXNetworkTransactionState) {
|
||||
/// Only applicable for image downloads. A small thumbnail to preview the full response.
|
||||
@property (nonatomic, strong) UIImage *responseThumbnail;
|
||||
|
||||
/// Populated lazily. Handles both normal HTTPBody data and HTTPBodyStreams.
|
||||
@property (nonatomic, strong, readonly) NSData *cachedRequestBody;
|
||||
|
||||
+ (NSString *)readableStringFromTransactionState:(FLEXNetworkTransactionState)state;
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
|
||||
#import "FLEXNetworkTransaction.h"
|
||||
|
||||
@interface FLEXNetworkTransaction ()
|
||||
|
||||
@property (nonatomic, strong, readwrite) NSData *cachedRequestBody;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXNetworkTransaction
|
||||
|
||||
- (NSString *)description
|
||||
@@ -22,6 +28,28 @@
|
||||
return description;
|
||||
}
|
||||
|
||||
- (NSData *)cachedRequestBody {
|
||||
if (!_cachedRequestBody) {
|
||||
if (self.request.HTTPBody != nil) {
|
||||
_cachedRequestBody = self.request.HTTPBody;
|
||||
} else if ([self.request.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) {
|
||||
NSInputStream *bodyStream = [self.request.HTTPBodyStream copy];
|
||||
const NSUInteger bufferSize = 1024;
|
||||
uint8_t buffer[bufferSize];
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
[bodyStream open];
|
||||
NSInteger readBytes = 0;
|
||||
do {
|
||||
readBytes = [bodyStream read:buffer maxLength:bufferSize];
|
||||
[data appendBytes:buffer length:readBytes];
|
||||
} while (readBytes > 0);
|
||||
[bodyStream close];
|
||||
_cachedRequestBody = data;
|
||||
}
|
||||
}
|
||||
return _cachedRequestBody;
|
||||
}
|
||||
|
||||
+ (NSString *)readableStringFromTransactionState:(FLEXNetworkTransactionState)state
|
||||
{
|
||||
NSString *readableString = nil;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import "FLEXNetworkTransactionDetailTableViewController.h"
|
||||
#import "FLEXNetworkCurlLogger.h"
|
||||
#import "FLEXNetworkRecorder.h"
|
||||
#import "FLEXNetworkTransaction.h"
|
||||
#import "FLEXWebViewController.h"
|
||||
@@ -14,17 +15,6 @@
|
||||
#import "FLEXMultilineTableViewCell.h"
|
||||
#import "FLEXUtility.h"
|
||||
|
||||
@interface FLEXNetworkDetailSection : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString *title;
|
||||
@property (nonatomic, copy) NSArray *rows;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXNetworkDetailSection
|
||||
|
||||
@end
|
||||
|
||||
typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
@interface FLEXNetworkDetailRow : NSObject
|
||||
@@ -39,9 +29,20 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
@end
|
||||
|
||||
@interface FLEXNetworkDetailSection : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString *title;
|
||||
@property (nonatomic, copy) NSArray<FLEXNetworkDetailRow *> *rows;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXNetworkDetailSection
|
||||
|
||||
@end
|
||||
|
||||
@interface FLEXNetworkTransactionDetailTableViewController ()
|
||||
|
||||
@property (nonatomic, copy) NSArray *sections;
|
||||
@property (nonatomic, copy) NSArray<FLEXNetworkDetailSection *> *sections;
|
||||
|
||||
@end
|
||||
|
||||
@@ -53,7 +54,7 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
self = [super initWithStyle:UITableViewStyleGrouped];
|
||||
if (self) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTransactionUpdatedNotification:) name:kFLEXNetworkRecorderTransactionUpdatedNotification object:nil];
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Copy" style:UIBarButtonItemStylePlain target:self action:@selector(copyButtonPressed:)];
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Copy curl" style:UIBarButtonItemStylePlain target:self action:@selector(copyButtonPressed:)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -74,7 +75,7 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSections:(NSArray *)sections
|
||||
- (void)setSections:(NSArray<FLEXNetworkDetailSection *> *)sections
|
||||
{
|
||||
if (![_sections isEqual:sections]) {
|
||||
_sections = [sections copy];
|
||||
@@ -84,7 +85,7 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
- (void)rebuildTableSections
|
||||
{
|
||||
NSMutableArray *sections = [NSMutableArray array];
|
||||
NSMutableArray<FLEXNetworkDetailSection *> *sections = [NSMutableArray array];
|
||||
|
||||
FLEXNetworkDetailSection *generalSection = [[self class] generalSectionForTransaction:self.transaction];
|
||||
if ([generalSection.rows count] > 0) {
|
||||
@@ -120,26 +121,7 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
- (void)copyButtonPressed:(id)sender
|
||||
{
|
||||
NSMutableString *requestDetailString = [NSMutableString string];
|
||||
|
||||
for (FLEXNetworkDetailSection *section in self.sections) {
|
||||
if ([section.rows count] > 0) {
|
||||
if ([section.title length] > 0) {
|
||||
[requestDetailString appendString:section.title];
|
||||
[requestDetailString appendString:@"\n\n"];
|
||||
}
|
||||
for (FLEXNetworkDetailRow *row in section.rows) {
|
||||
NSString *rowDescription = [[[self class] attributedTextForRow:row] string];
|
||||
if ([rowDescription length] > 0) {
|
||||
[requestDetailString appendString:rowDescription];
|
||||
[requestDetailString appendString:@"\n"];
|
||||
}
|
||||
}
|
||||
[requestDetailString appendString:@"\n\n"];
|
||||
}
|
||||
}
|
||||
|
||||
[[UIPasteboard generalPasteboard] setString:requestDetailString];
|
||||
[[UIPasteboard generalPasteboard] setString:[FLEXNetworkCurlLogger curlCommandString:_transaction.request]];
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
@@ -228,10 +210,10 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
+ (NSAttributedString *)attributedTextForRow:(FLEXNetworkDetailRow *)row
|
||||
{
|
||||
NSDictionary *titleAttributes = @{ NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue-Medium" size:12.0],
|
||||
NSForegroundColorAttributeName : [UIColor colorWithWhite:0.5 alpha:1.0] };
|
||||
NSDictionary *detailAttributes = @{ NSFontAttributeName : [FLEXUtility defaultTableViewCellLabelFont],
|
||||
NSForegroundColorAttributeName : [UIColor blackColor] };
|
||||
NSDictionary<NSString *, id> *titleAttributes = @{ NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue-Medium" size:12.0],
|
||||
NSForegroundColorAttributeName : [UIColor colorWithWhite:0.5 alpha:1.0] };
|
||||
NSDictionary<NSString *, id> *detailAttributes = @{ NSFontAttributeName : [FLEXUtility defaultTableViewCellLabelFont],
|
||||
NSForegroundColorAttributeName : [UIColor blackColor] };
|
||||
|
||||
NSString *title = [NSString stringWithFormat:@"%@: ", row.title];
|
||||
NSString *detailText = row.detailText ?: @"";
|
||||
@@ -246,7 +228,7 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
+ (FLEXNetworkDetailSection *)generalSectionForTransaction:(FLEXNetworkTransaction *)transaction
|
||||
{
|
||||
NSMutableArray *rows = [NSMutableArray array];
|
||||
NSMutableArray<FLEXNetworkDetailRow *> *rows = [NSMutableArray array];
|
||||
|
||||
FLEXNetworkDetailRow *requestURLRow = [[FLEXNetworkDetailRow alloc] init];
|
||||
requestURLRow.title = @"Request URL";
|
||||
@@ -264,10 +246,10 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
requestMethodRow.detailText = transaction.request.HTTPMethod;
|
||||
[rows addObject:requestMethodRow];
|
||||
|
||||
if ([transaction.request.HTTPBody length] > 0) {
|
||||
if ([transaction.cachedRequestBody length] > 0) {
|
||||
FLEXNetworkDetailRow *postBodySizeRow = [[FLEXNetworkDetailRow alloc] init];
|
||||
postBodySizeRow.title = @"Request Body Size";
|
||||
postBodySizeRow.detailText = [NSByteCountFormatter stringFromByteCount:[transaction.request.HTTPBody length] countStyle:NSByteCountFormatterCountStyleBinary];
|
||||
postBodySizeRow.detailText = [NSByteCountFormatter stringFromByteCount:[transaction.cachedRequestBody length] countStyle:NSByteCountFormatterCountStyleBinary];
|
||||
[rows addObject:postBodySizeRow];
|
||||
|
||||
FLEXNetworkDetailRow *postBodyRow = [[FLEXNetworkDetailRow alloc] init];
|
||||
@@ -396,7 +378,7 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
{
|
||||
FLEXNetworkDetailSection *postBodySection = [[FLEXNetworkDetailSection alloc] init];
|
||||
postBodySection.title = @"Request Body Parameters";
|
||||
if ([transaction.request.HTTPBody length] > 0) {
|
||||
if ([transaction.cachedRequestBody length] > 0) {
|
||||
NSString *contentType = [transaction.request valueForHTTPHeaderField:@"Content-Type"];
|
||||
if ([contentType hasPrefix:@"application/x-www-form-urlencoded"]) {
|
||||
NSString *bodyString = [[NSString alloc] initWithData:[self postBodyDataForTransaction:transaction] encoding:NSUTF8StringEncoding];
|
||||
@@ -408,7 +390,7 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
+ (FLEXNetworkDetailSection *)queryParametersSectionForTransaction:(FLEXNetworkTransaction *)transaction
|
||||
{
|
||||
NSDictionary *queryDictionary = [FLEXUtility dictionaryFromQuery:transaction.request.URL.query];
|
||||
NSDictionary<NSString *, id> *queryDictionary = [FLEXUtility dictionaryFromQuery:transaction.request.URL.query];
|
||||
FLEXNetworkDetailSection *querySection = [[FLEXNetworkDetailSection alloc] init];
|
||||
querySection.title = @"Query Parameters";
|
||||
querySection.rows = [self networkDetailRowsFromDictionary:queryDictionary];
|
||||
@@ -427,12 +409,12 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
return responseHeadersSection;
|
||||
}
|
||||
|
||||
+ (NSArray *)networkDetailRowsFromDictionary:(NSDictionary *)dictionary
|
||||
+ (NSArray<FLEXNetworkDetailRow *> *)networkDetailRowsFromDictionary:(NSDictionary<NSString *, id> *)dictionary
|
||||
{
|
||||
NSMutableArray *rows = [NSMutableArray arrayWithCapacity:[dictionary count]];
|
||||
NSArray *sortedKeys = [[dictionary allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
|
||||
NSMutableArray<FLEXNetworkDetailRow *> *rows = [NSMutableArray arrayWithCapacity:[dictionary count]];
|
||||
NSArray<NSString *> *sortedKeys = [[dictionary allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
|
||||
for (NSString *key in sortedKeys) {
|
||||
NSString *value = dictionary[key];
|
||||
id value = dictionary[key];
|
||||
FLEXNetworkDetailRow *row = [[FLEXNetworkDetailRow alloc] init];
|
||||
row.title = key;
|
||||
row.detailText = [value description];
|
||||
@@ -470,7 +452,7 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
+ (NSData *)postBodyDataForTransaction:(FLEXNetworkTransaction *)transaction
|
||||
{
|
||||
NSData *bodyData = transaction.request.HTTPBody;
|
||||
NSData *bodyData = transaction.cachedRequestBody;
|
||||
if ([bodyData length] > 0) {
|
||||
NSString *contentEncoding = [transaction.request valueForHTTPHeaderField:@"Content-Encoding"];
|
||||
if ([contentEncoding rangeOfString:@"deflate" options:NSCaseInsensitiveSearch].length > 0 || [contentEncoding rangeOfString:@"gzip" options:NSCaseInsensitiveSearch].length > 0) {
|
||||
|
||||
@@ -79,7 +79,7 @@ NSString *const kFLEXNetworkTransactionCellIdentifier = @"kFLEXNetworkTransactio
|
||||
self.nameLabel.text = [self nameLabelText];
|
||||
CGSize nameLabelPreferredSize = [self.nameLabel sizeThatFits:CGSizeMake(availableTextWidth, CGFLOAT_MAX)];
|
||||
self.nameLabel.frame = CGRectMake(textOriginX, kVerticalPadding, availableTextWidth, nameLabelPreferredSize.height);
|
||||
self.nameLabel.textColor = self.transaction.error ? [UIColor redColor] : [UIColor blackColor];
|
||||
self.nameLabel.textColor = (self.transaction.error || [FLEXUtility isErrorStatusCodeFromURLResponse:self.transaction.response]) ? [UIColor redColor] : [UIColor blackColor];
|
||||
|
||||
self.pathLabel.text = [self pathLabelText];
|
||||
CGSize pathLabelPreferredSize = [self.pathLabel sizeThatFits:CGSizeMake(availableTextWidth, CGFLOAT_MAX)];
|
||||
@@ -111,7 +111,7 @@ NSString *const kFLEXNetworkTransactionCellIdentifier = @"kFLEXNetworkTransactio
|
||||
- (NSString *)pathLabelText
|
||||
{
|
||||
NSURL *url = self.transaction.request.URL;
|
||||
NSMutableArray *mutablePathComponents = [[url pathComponents] mutableCopy];
|
||||
NSMutableArray<NSString *> *mutablePathComponents = [[url pathComponents] mutableCopy];
|
||||
if ([mutablePathComponents count] > 0) {
|
||||
[mutablePathComponents removeLastObject];
|
||||
}
|
||||
@@ -124,7 +124,7 @@ NSString *const kFLEXNetworkTransactionCellIdentifier = @"kFLEXNetworkTransactio
|
||||
|
||||
- (NSString *)transactionDetailsLabelText
|
||||
{
|
||||
NSMutableArray *detailComponents = [NSMutableArray array];
|
||||
NSMutableArray<NSString *> *detailComponents = [NSMutableArray array];
|
||||
|
||||
NSString *timestamp = [[self class] timestampStringFromRequestDate:self.transaction.startTime];
|
||||
if ([timestamp length] > 0) {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern NSString *const kFLEXNetworkObserverEnabledStateChangedNotification;
|
||||
FOUNDATION_EXTERN NSString *const kFLEXNetworkObserverEnabledStateChangedNotification;
|
||||
|
||||
/// This class swizzles NSURLConnection and NSURLSession delegate methods to observe events in the URL loading system.
|
||||
/// High level network events are sent to the default FLEXNetworkRecorder instance which maintains the request history and caches response bodies.
|
||||
|
||||
@@ -68,7 +68,7 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id <NSU
|
||||
|
||||
@interface FLEXNetworkObserver ()
|
||||
|
||||
@property (nonatomic, strong) NSMutableDictionary *requestStatesForRequestIDs;
|
||||
@property (nonatomic, strong) NSMutableDictionary<NSString *, FLEXInternalRequestState *> *requestStatesForRequestIDs;
|
||||
@property (nonatomic, strong) dispatch_queue_t queue;
|
||||
|
||||
@end
|
||||
@@ -172,7 +172,7 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id <NSU
|
||||
@selector(URLSession:dataTask:didReceiveData:),
|
||||
@selector(URLSession:dataTask:didReceiveResponse:completionHandler:),
|
||||
@selector(URLSession:task:didCompleteWithError:),
|
||||
@selector(URLSession:dataTask:didBecomeDownloadTask:delegate:),
|
||||
@selector(URLSession:dataTask:didBecomeDownloadTask:),
|
||||
@selector(URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:),
|
||||
@selector(URLSession:downloadTask:didFinishDownloadingToURL:)
|
||||
};
|
||||
@@ -318,7 +318,7 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id <NSU
|
||||
if ([FLEXNetworkObserver isEnabled]) {
|
||||
NSString *requestID = [self nextRequestID];
|
||||
[[FLEXNetworkRecorder defaultRecorder] recordRequestWillBeSentWithRequestID:requestID request:request redirectResponse:nil];
|
||||
NSString *mechanism = [self mechansimFromClassMethod:selector onClass:class];
|
||||
NSString *mechanism = [self mechanismFromClassMethod:selector onClass:class];
|
||||
[[FLEXNetworkRecorder defaultRecorder] recordMechanism:mechanism forRequestID:requestID];
|
||||
NSURLConnectionAsyncCompletion completionWrapper = ^(NSURLResponse *response, NSData *data, NSError *connectionError) {
|
||||
[[FLEXNetworkRecorder defaultRecorder] recordResponseReceivedWithRequestID:requestID response:response];
|
||||
@@ -357,7 +357,7 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id <NSU
|
||||
if ([FLEXNetworkObserver isEnabled]) {
|
||||
NSString *requestID = [self nextRequestID];
|
||||
[[FLEXNetworkRecorder defaultRecorder] recordRequestWillBeSentWithRequestID:requestID request:request redirectResponse:nil];
|
||||
NSString *mechanism = [self mechansimFromClassMethod:selector onClass:class];
|
||||
NSString *mechanism = [self mechanismFromClassMethod:selector onClass:class];
|
||||
[[FLEXNetworkRecorder defaultRecorder] recordMechanism:mechanism forRequestID:requestID];
|
||||
NSError *temporaryError = nil;
|
||||
NSURLResponse *temporaryResponse = nil;
|
||||
@@ -420,7 +420,7 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id <NSU
|
||||
// with nil completion block.
|
||||
if ([FLEXNetworkObserver isEnabled] && completion) {
|
||||
NSString *requestID = [self nextRequestID];
|
||||
NSString *mechanism = [self mechansimFromClassMethod:selector onClass:class];
|
||||
NSString *mechanism = [self mechanismFromClassMethod:selector onClass:class];
|
||||
NSURLSessionAsyncCompletion completionWrapper = [self asyncCompletionWrapperForRequestID:requestID mechanism:mechanism completion:completion];
|
||||
task = ((id(*)(id, SEL, id, id))objc_msgSend)(slf, swizzledSelector, argument, completionWrapper);
|
||||
[self setRequestID:requestID forConnectionOrTask:task];
|
||||
@@ -462,9 +462,9 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id <NSU
|
||||
|
||||
NSURLSessionUploadTask *(^asyncUploadTaskSwizzleBlock)(Class, NSURLRequest *, id, NSURLSessionAsyncCompletion) = ^NSURLSessionUploadTask *(Class slf, NSURLRequest *request, id argument, NSURLSessionAsyncCompletion completion) {
|
||||
NSURLSessionUploadTask *task = nil;
|
||||
if ([FLEXNetworkObserver isEnabled]) {
|
||||
if ([FLEXNetworkObserver isEnabled] && completion) {
|
||||
NSString *requestID = [self nextRequestID];
|
||||
NSString *mechanism = [self mechansimFromClassMethod:selector onClass:class];
|
||||
NSString *mechanism = [self mechanismFromClassMethod:selector onClass:class];
|
||||
NSURLSessionAsyncCompletion completionWrapper = [self asyncCompletionWrapperForRequestID:requestID mechanism:mechanism completion:completion];
|
||||
task = ((id(*)(id, SEL, id, id, id))objc_msgSend)(slf, swizzledSelector, request, argument, completionWrapper);
|
||||
[self setRequestID:requestID forConnectionOrTask:task];
|
||||
@@ -479,7 +479,7 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id <NSU
|
||||
});
|
||||
}
|
||||
|
||||
+ (NSString *)mechansimFromClassMethod:(SEL)selector onClass:(Class)class
|
||||
+ (NSString *)mechanismFromClassMethod:(SEL)selector onClass:(Class)class
|
||||
{
|
||||
return [NSString stringWithFormat:@"+[%@ %@]", NSStringFromClass(class), NSStringFromSelector(selector)];
|
||||
}
|
||||
@@ -667,13 +667,14 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id <NSU
|
||||
|
||||
NSURLSessionWillPerformHTTPRedirectionBlock undefinedBlock = ^(id <NSURLSessionTaskDelegate> slf, NSURLSession *session, NSURLSessionTask *task, NSHTTPURLResponse *response, NSURLRequest *newRequest, void(^completionHandler)(NSURLRequest *)) {
|
||||
[[FLEXNetworkObserver sharedObserver] URLSession:session task:task willPerformHTTPRedirection:response newRequest:newRequest completionHandler:completionHandler delegate:slf];
|
||||
completionHandler(newRequest);
|
||||
};
|
||||
|
||||
NSURLSessionWillPerformHTTPRedirectionBlock implementationBlock = ^(id <NSURLSessionTaskDelegate> slf, NSURLSession *session, NSURLSessionTask *task, NSHTTPURLResponse *response, NSURLRequest *newRequest, void(^completionHandler)(NSURLRequest *)) {
|
||||
[self sniffWithoutDuplicationForObject:session selector:selector sniffingBlock:^{
|
||||
undefinedBlock(slf, session, task, response, newRequest, completionHandler);
|
||||
[[FLEXNetworkObserver sharedObserver] URLSession:session task:task willPerformHTTPRedirection:response newRequest:newRequest completionHandler:completionHandler delegate:slf];
|
||||
} originalImplementationBlock:^{
|
||||
((id(*)(id, SEL, id, id, id, id, void(^)()))objc_msgSend)(slf, swizzledSelector, session, task, response, newRequest, completionHandler);
|
||||
((id(*)(id, SEL, id, id, id, id, void(^)(NSURLRequest *)))objc_msgSend)(slf, swizzledSelector, session, task, response, newRequest, completionHandler);
|
||||
}];
|
||||
};
|
||||
|
||||
@@ -747,13 +748,14 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask delegate:(id <NSU
|
||||
|
||||
NSURLSessionDidReceiveResponseBlock undefinedBlock = ^(id <NSURLSessionDelegate> slf, NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response, void(^completionHandler)(NSURLSessionResponseDisposition disposition)) {
|
||||
[[FLEXNetworkObserver sharedObserver] URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler delegate:slf];
|
||||
completionHandler(NSURLSessionResponseAllow);
|
||||
};
|
||||
|
||||
NSURLSessionDidReceiveResponseBlock implementationBlock = ^(id <NSURLSessionDelegate> slf, NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response, void(^completionHandler)(NSURLSessionResponseDisposition disposition)) {
|
||||
[self sniffWithoutDuplicationForObject:session selector:selector sniffingBlock:^{
|
||||
undefinedBlock(slf, session, dataTask, response, completionHandler);
|
||||
[[FLEXNetworkObserver sharedObserver] URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler delegate:slf];
|
||||
} originalImplementationBlock:^{
|
||||
((void(*)(id, SEL, id, id, id, void(^)()))objc_msgSend)(slf, swizzledSelector, session, dataTask, response, completionHandler);
|
||||
((void(*)(id, SEL, id, id, id, void(^)(NSURLSessionResponseDisposition)))objc_msgSend)(slf, swizzledSelector, session, dataTask, response, completionHandler);
|
||||
}];
|
||||
};
|
||||
|
||||
@@ -942,7 +944,7 @@ static char const * const kFLEXRequestIDKey = "kFLEXRequestIDKey";
|
||||
NSMutableData *dataAccumulator = nil;
|
||||
if (response.expectedContentLength < 0) {
|
||||
dataAccumulator = [[NSMutableData alloc] init];
|
||||
} else {
|
||||
} else if (response.expectedContentLength < 52428800) {
|
||||
dataAccumulator = [[NSMutableData alloc] initWithCapacity:(NSUInteger)response.expectedContentLength];
|
||||
}
|
||||
requestState.dataAccumulator = dataAccumulator;
|
||||
@@ -993,7 +995,7 @@ static char const * const kFLEXRequestIDKey = "kFLEXRequestIDKey";
|
||||
{
|
||||
[self performBlock:^{
|
||||
// Mimic the behavior of NSURLSession which is to create an error on cancellation.
|
||||
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : @"cancelled" };
|
||||
NSDictionary<NSString *, id> *userInfo = @{ NSLocalizedDescriptionKey : @"cancelled" };
|
||||
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo];
|
||||
[self connection:connection didFailWithError:error delegate:nil];
|
||||
}];
|
||||
|
||||
@@ -35,11 +35,11 @@ typedef NS_ENUM(NSUInteger, FLEXClassExplorerRow) {
|
||||
|
||||
#pragma mark - Superclass Overrides
|
||||
|
||||
- (NSArray *)possibleExplorerSections
|
||||
- (NSArray<NSNumber *> *)possibleExplorerSections
|
||||
{
|
||||
// Move class methods to between our custom section and the properties section since
|
||||
// we are more interested in the class sections than in the instance level sections.
|
||||
NSMutableArray *mutableSections = [[super possibleExplorerSections] mutableCopy];
|
||||
NSMutableArray<NSNumber *> *mutableSections = [[super possibleExplorerSections] mutableCopy];
|
||||
[mutableSections removeObject:@(FLEXObjectExplorerSectionClassMethods)];
|
||||
[mutableSections insertObject:@(FLEXObjectExplorerSectionClassMethods) atIndex:[mutableSections indexOfObject:@(FLEXObjectExplorerSectionProperties)]];
|
||||
return mutableSections;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// FLEXColorExplorerViewController.h
|
||||
// Flipboard
|
||||
//
|
||||
// Created by Tanner on 10/18/18.
|
||||
// Copyright © 2018 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXObjectExplorerViewController.h"
|
||||
|
||||
@interface FLEXColorExplorerViewController : FLEXObjectExplorerViewController
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// FLEXColorExplorerViewController.m
|
||||
// Flipboard
|
||||
//
|
||||
// Created by Tanner on 10/18/18.
|
||||
// Copyright © 2018 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXColorExplorerViewController.h"
|
||||
|
||||
@interface FLEXColorExplorerViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXColorExplorerViewController
|
||||
|
||||
- (BOOL)shouldShowDescription
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *)customSectionTitle
|
||||
{
|
||||
return @"Color";
|
||||
}
|
||||
|
||||
- (NSArray *)customSectionRowCookies
|
||||
{
|
||||
return @[@0];
|
||||
}
|
||||
|
||||
- (UIView *)customViewForRowCookie:(id)rowCookie
|
||||
{
|
||||
CGFloat width = [UIScreen mainScreen].bounds.size.width;
|
||||
UIView *square = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 44)];
|
||||
square.backgroundColor = (UIColor *)self.object;
|
||||
return square;
|
||||
}
|
||||
|
||||
//- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||
// if (indexPath.section == 0 && indexPath.row == 0) {
|
||||
// cell.contentView.backgroundColor = (UIColor *)self.object;
|
||||
// }
|
||||
//
|
||||
// return cell;
|
||||
//}
|
||||
|
||||
@end
|
||||
@@ -17,6 +17,7 @@
|
||||
#import "FLEXImageExplorerViewController.h"
|
||||
#import "FLEXClassExplorerViewController.h"
|
||||
#import "FLEXLayerExplorerViewController.h"
|
||||
#import "FLEXColorExplorerViewController.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation FLEXObjectExplorerFactory
|
||||
@@ -28,7 +29,7 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
static NSDictionary *explorerSubclassesForObjectTypeStrings = nil;
|
||||
static NSDictionary<NSString *, Class> *explorerSubclassesForObjectTypeStrings = nil;
|
||||
static dispatch_once_t once;
|
||||
dispatch_once(&once, ^{
|
||||
explorerSubclassesForObjectTypeStrings = @{NSStringFromClass([NSArray class]) : [FLEXArrayExplorerViewController class],
|
||||
@@ -38,7 +39,9 @@
|
||||
NSStringFromClass([UIViewController class]) : [FLEXViewControllerExplorerViewController class],
|
||||
NSStringFromClass([UIView class]) : [FLEXViewExplorerViewController class],
|
||||
NSStringFromClass([UIImage class]) : [FLEXImageExplorerViewController class],
|
||||
NSStringFromClass([CALayer class]) : [FLEXLayerExplorerViewController class]};
|
||||
NSStringFromClass([CALayer class]) : [FLEXLayerExplorerViewController class],
|
||||
NSStringFromClass([UIColor class]) : [FLEXColorExplorerViewController class]
|
||||
};
|
||||
});
|
||||
|
||||
Class explorerClass = nil;
|
||||
|
||||
@@ -33,6 +33,7 @@ typedef NS_ENUM(NSUInteger, FLEXObjectExplorerSection) {
|
||||
- (NSString *)customSectionSubtitleForRowCookie:(id)rowCookie;
|
||||
- (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie;
|
||||
- (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie;
|
||||
- (UIView *)customViewForRowCookie:(id)rowCookie;
|
||||
|
||||
// More subclass configuration hooks.
|
||||
|
||||
|
||||
@@ -17,6 +17,20 @@
|
||||
#import "FLEXInstancesTableViewController.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FLEXObjectExplorerScope) {
|
||||
FLEXObjectExplorerScopeNoInheritance,
|
||||
FLEXObjectExplorerScopeWithParent,
|
||||
FLEXObjectExplorerScopeAllButNSObject,
|
||||
FLEXObjectExplorerScopeNSObjectOnly
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
|
||||
FLEXMetadataKindProperties,
|
||||
FLEXMetadataKindIvars,
|
||||
FLEXMetadataKindMethods,
|
||||
FLEXMetadataKindClassMethods
|
||||
};
|
||||
|
||||
// Convenience boxes to keep runtime properties, ivars, and methods in foundation collections.
|
||||
@interface FLEXPropertyBox : NSObject
|
||||
@property (nonatomic, assign) objc_property_t property;
|
||||
@@ -36,36 +50,41 @@
|
||||
@implementation FLEXMethodBox
|
||||
@end
|
||||
|
||||
static const NSInteger kFLEXObjectExplorerScopeNoInheritanceIndex = 0;
|
||||
static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
|
||||
@interface FLEXObjectExplorerViewController () <UISearchBarDelegate>
|
||||
|
||||
@property (nonatomic, strong) NSArray *properties;
|
||||
@property (nonatomic, strong) NSArray *inheritedProperties;
|
||||
@property (nonatomic, strong) NSArray *filteredProperties;
|
||||
@property (nonatomic, strong) NSArray<FLEXPropertyBox *> *properties;
|
||||
@property (nonatomic, strong) NSArray<FLEXPropertyBox *> *propertiesWithParent;
|
||||
@property (nonatomic, strong) NSArray<FLEXPropertyBox *> *inheritedProperties;
|
||||
@property (nonatomic, strong) NSArray<FLEXPropertyBox *> *NSObjectProperties;
|
||||
@property (nonatomic, strong) NSArray<FLEXPropertyBox *> *filteredProperties;
|
||||
|
||||
@property (nonatomic, strong) NSArray *ivars;
|
||||
@property (nonatomic, strong) NSArray *inheritedIvars;
|
||||
@property (nonatomic, strong) NSArray *filteredIvars;
|
||||
@property (nonatomic, strong) NSArray<FLEXIvarBox *> *ivars;
|
||||
@property (nonatomic, strong) NSArray<FLEXIvarBox *> *ivarsWithParent;
|
||||
@property (nonatomic, strong) NSArray<FLEXIvarBox *> *inheritedIvars;
|
||||
@property (nonatomic, strong) NSArray<FLEXIvarBox *> *NSObjectIvars;
|
||||
@property (nonatomic, strong) NSArray<FLEXIvarBox *> *filteredIvars;
|
||||
|
||||
@property (nonatomic, strong) NSArray *methods;
|
||||
@property (nonatomic, strong) NSArray *inheritedMethods;
|
||||
@property (nonatomic, strong) NSArray *filteredMethods;
|
||||
@property (nonatomic, strong) NSArray<FLEXMethodBox *> *methods;
|
||||
@property (nonatomic, strong) NSArray<FLEXMethodBox *> *methodsWithParent;
|
||||
@property (nonatomic, strong) NSArray<FLEXMethodBox *> *inheritedMethods;
|
||||
@property (nonatomic, strong) NSArray<FLEXMethodBox *> *NSObjectMethods;
|
||||
@property (nonatomic, strong) NSArray<FLEXMethodBox *> *filteredMethods;
|
||||
|
||||
@property (nonatomic, strong) NSArray *classMethods;
|
||||
@property (nonatomic, strong) NSArray *inheritedClassMethods;
|
||||
@property (nonatomic, strong) NSArray *filteredClassMethods;
|
||||
@property (nonatomic, strong) NSArray<FLEXMethodBox *> *classMethods;
|
||||
@property (nonatomic, strong) NSArray<FLEXMethodBox *> *classMethodsWithParent;
|
||||
@property (nonatomic, strong) NSArray<FLEXMethodBox *> *inheritedClassMethods;
|
||||
@property (nonatomic, strong) NSArray<FLEXMethodBox *> *NSObjectClassMethods;
|
||||
@property (nonatomic, strong) NSArray<FLEXMethodBox *> *filteredClassMethods;
|
||||
|
||||
@property (nonatomic, strong) NSArray *superclasses;
|
||||
@property (nonatomic, strong) NSArray *filteredSuperclasses;
|
||||
@property (nonatomic, strong) NSArray<Class> *superclasses;
|
||||
@property (nonatomic, strong) NSArray<Class> *filteredSuperclasses;
|
||||
|
||||
@property (nonatomic, strong) NSArray *cachedCustomSectionRowCookies;
|
||||
@property (nonatomic, strong) NSIndexSet *customSectionVisibleIndexes;
|
||||
|
||||
@property (nonatomic, strong) UISearchBar *searchBar;
|
||||
@property (nonatomic, strong) NSString *filterText;
|
||||
@property (nonatomic, assign) BOOL includeInheritance;
|
||||
@property (nonatomic, assign) FLEXObjectExplorerScope scope;
|
||||
|
||||
@end
|
||||
|
||||
@@ -85,8 +104,7 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
self.searchBar.placeholder = [FLEXUtility searchBarPlaceholderText];
|
||||
self.searchBar.delegate = self;
|
||||
self.searchBar.showsScopeBar = YES;
|
||||
self.searchBar.scopeButtonTitles = @[@"No Inheritance", @"Include Inheritance"];
|
||||
[self.searchBar sizeToFit];
|
||||
[self refreshScopeTitles];
|
||||
self.tableView.tableHeaderView = self.searchBar;
|
||||
|
||||
self.refreshControl = [[UIRefreshControl alloc] init];
|
||||
@@ -116,6 +134,28 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
|
||||
#pragma mark - Search
|
||||
|
||||
- (void)refreshScopeTitles {
|
||||
if (!self.searchBar) return;
|
||||
|
||||
Class parent = [self.object superclass];
|
||||
Class parentSuper = [parent superclass];
|
||||
|
||||
NSMutableArray *scopes = [NSMutableArray arrayWithObject:@"Base"];
|
||||
if (parent) {
|
||||
[scopes addObject:@"+ Parent"];
|
||||
}
|
||||
if (parentSuper && parentSuper != [NSObject class]) {
|
||||
[scopes addObject:@"+ Inherited"];
|
||||
}
|
||||
if ([self.object isKindOfClass:[NSObject class]]) {
|
||||
[scopes addObject:@"NSObject"];
|
||||
}
|
||||
|
||||
self.searchBar.scopeButtonTitles = scopes;
|
||||
[self.searchBar sizeToFit];
|
||||
[self updateTableData];
|
||||
}
|
||||
|
||||
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
|
||||
{
|
||||
self.filterText = searchText;
|
||||
@@ -128,13 +168,62 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
|
||||
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope
|
||||
{
|
||||
if (selectedScope == kFLEXObjectExplorerScopeIncludeInheritanceIndex) {
|
||||
self.includeInheritance = YES;
|
||||
} else if (selectedScope == kFLEXObjectExplorerScopeNoInheritanceIndex) {
|
||||
self.includeInheritance = NO;
|
||||
self.scope = selectedScope;
|
||||
[self updateDisplayedData];
|
||||
}
|
||||
|
||||
- (NSArray *)metadata:(FLEXMetadataKind)metadataKind forScope:(FLEXObjectExplorerScope)scope {
|
||||
switch (metadataKind) {
|
||||
case FLEXMetadataKindProperties:
|
||||
switch (self.scope) {
|
||||
case FLEXObjectExplorerScopeNoInheritance:
|
||||
return self.properties;
|
||||
case FLEXObjectExplorerScopeWithParent:
|
||||
return self.propertiesWithParent;
|
||||
case FLEXObjectExplorerScopeAllButNSObject:
|
||||
return self.inheritedProperties;
|
||||
case FLEXObjectExplorerScopeNSObjectOnly:
|
||||
return self.NSObjectProperties;
|
||||
}
|
||||
case FLEXMetadataKindIvars:
|
||||
switch (self.scope) {
|
||||
case FLEXObjectExplorerScopeNoInheritance:
|
||||
return self.ivars;
|
||||
case FLEXObjectExplorerScopeWithParent:
|
||||
return self.ivarsWithParent;
|
||||
case FLEXObjectExplorerScopeAllButNSObject:
|
||||
return self.inheritedIvars;
|
||||
case FLEXObjectExplorerScopeNSObjectOnly:
|
||||
return self.NSObjectIvars;
|
||||
}
|
||||
case FLEXMetadataKindMethods:
|
||||
switch (self.scope) {
|
||||
case FLEXObjectExplorerScopeNoInheritance:
|
||||
return self.methods;
|
||||
case FLEXObjectExplorerScopeWithParent:
|
||||
return self.methodsWithParent;
|
||||
case FLEXObjectExplorerScopeAllButNSObject:
|
||||
return self.inheritedMethods;
|
||||
case FLEXObjectExplorerScopeNSObjectOnly:
|
||||
return self.NSObjectMethods;
|
||||
}
|
||||
case FLEXMetadataKindClassMethods:
|
||||
switch (self.scope) {
|
||||
case FLEXObjectExplorerScopeNoInheritance:
|
||||
return self.classMethods;
|
||||
case FLEXObjectExplorerScopeWithParent:
|
||||
return self.classMethodsWithParent;
|
||||
case FLEXObjectExplorerScopeAllButNSObject:
|
||||
return self.inheritedClassMethods;
|
||||
case FLEXObjectExplorerScopeNSObjectOnly:
|
||||
return self.NSObjectClassMethods;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)totalCountOfMetadata:(FLEXMetadataKind)metadataKind forScope:(FLEXObjectExplorerScope)scope {
|
||||
return [self metadata:metadataKind forScope:scope].count;
|
||||
}
|
||||
|
||||
#pragma mark - Setter overrides
|
||||
|
||||
@@ -143,15 +232,7 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
_object = object;
|
||||
// Use [object class] here rather than object_getClass because we don't want to show the KVO prefix for observed objects.
|
||||
self.title = [[object class] description];
|
||||
[self updateTableData];
|
||||
}
|
||||
|
||||
- (void)setIncludeInheritance:(BOOL)includeInheritance
|
||||
{
|
||||
if (_includeInheritance != includeInheritance) {
|
||||
_includeInheritance = includeInheritance;
|
||||
[self updateDisplayedData];
|
||||
}
|
||||
[self refreshScopeTitles];
|
||||
}
|
||||
|
||||
- (void)setFilterText:(NSString *)filterText
|
||||
@@ -215,12 +296,18 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
{
|
||||
Class class = [self.object class];
|
||||
self.properties = [[self class] propertiesForClass:class];
|
||||
self.inheritedProperties = [[self class] inheritedPropertiesForClass:class];
|
||||
self.propertiesWithParent = [self.properties arrayByAddingObjectsFromArray:[[self class] propertiesForClass:[class superclass]]];
|
||||
self.inheritedProperties = [self.properties arrayByAddingObjectsFromArray:[[self class] inheritedPropertiesForClass:class]];
|
||||
self.NSObjectProperties = [[self class] propertiesForClass:[NSObject class]];
|
||||
}
|
||||
|
||||
+ (NSArray *)propertiesForClass:(Class)class
|
||||
+ (NSArray<FLEXPropertyBox *> *)propertiesForClass:(Class)class
|
||||
{
|
||||
NSMutableArray *boxedProperties = [NSMutableArray array];
|
||||
if (!class) {
|
||||
return @[];
|
||||
}
|
||||
|
||||
NSMutableArray<FLEXPropertyBox *> *boxedProperties = [NSMutableArray array];
|
||||
unsigned int propertyCount = 0;
|
||||
objc_property_t *propertyList = class_copyPropertyList(class, &propertyCount);
|
||||
if (propertyList) {
|
||||
@@ -234,10 +321,11 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
return boxedProperties;
|
||||
}
|
||||
|
||||
+ (NSArray *)inheritedPropertiesForClass:(Class)class
|
||||
/// Skips NSObject
|
||||
+ (NSArray<FLEXPropertyBox *> *)inheritedPropertiesForClass:(Class)class
|
||||
{
|
||||
NSMutableArray *inheritedProperties = [NSMutableArray array];
|
||||
while ((class = [class superclass])) {
|
||||
NSMutableArray<FLEXPropertyBox *> *inheritedProperties = [NSMutableArray array];
|
||||
while ((class = [class superclass]) && class != [NSObject class]) {
|
||||
[inheritedProperties addObjectsFromArray:[self propertiesForClass:class]];
|
||||
}
|
||||
return inheritedProperties;
|
||||
@@ -245,14 +333,11 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
|
||||
- (void)updateFilteredProperties
|
||||
{
|
||||
NSArray *candidateProperties = self.properties;
|
||||
if (self.includeInheritance) {
|
||||
candidateProperties = [candidateProperties arrayByAddingObjectsFromArray:self.inheritedProperties];
|
||||
}
|
||||
NSArray<FLEXPropertyBox *> *candidateProperties = [self metadata:FLEXMetadataKindProperties forScope:self.scope];
|
||||
|
||||
NSArray *unsortedFilteredProperties = nil;
|
||||
NSArray<FLEXPropertyBox *> *unsortedFilteredProperties = nil;
|
||||
if ([self.filterText length] > 0) {
|
||||
NSMutableArray *mutableUnsortedFilteredProperties = [NSMutableArray array];
|
||||
NSMutableArray<FLEXPropertyBox *> *mutableUnsortedFilteredProperties = [NSMutableArray array];
|
||||
for (FLEXPropertyBox *propertyBox in candidateProperties) {
|
||||
NSString *prettyName = [FLEXRuntimeUtility prettyNameForProperty:propertyBox.property];
|
||||
if ([prettyName rangeOfString:self.filterText options:NSCaseInsensitiveSearch].location != NSNotFound) {
|
||||
@@ -282,7 +367,10 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
id value = nil;
|
||||
if ([self canHaveInstanceState]) {
|
||||
FLEXPropertyBox *propertyBox = self.filteredProperties[index];
|
||||
NSString *typeString = [FLEXRuntimeUtility typeEncodingForProperty:propertyBox.property];
|
||||
const FLEXTypeEncoding *encoding = [typeString cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
value = [FLEXRuntimeUtility valueForProperty:propertyBox.property onObject:self.object];
|
||||
value = [FLEXRuntimeUtility potentiallyUnwrapBoxedPointer:value type:encoding];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -294,12 +382,17 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
{
|
||||
Class class = [self.object class];
|
||||
self.ivars = [[self class] ivarsForClass:class];
|
||||
self.inheritedIvars = [[self class] inheritedIvarsForClass:class];
|
||||
self.ivarsWithParent = [self.ivars arrayByAddingObjectsFromArray:[[self class] ivarsForClass:[class superclass]]];
|
||||
self.inheritedIvars = [self.ivars arrayByAddingObjectsFromArray:[[self class] inheritedIvarsForClass:class]];
|
||||
self.NSObjectIvars = [[self class] ivarsForClass:[NSObject class]];
|
||||
}
|
||||
|
||||
+ (NSArray *)ivarsForClass:(Class)class
|
||||
+ (NSArray<FLEXIvarBox *> *)ivarsForClass:(Class)class
|
||||
{
|
||||
NSMutableArray *boxedIvars = [NSMutableArray array];
|
||||
if (!class) {
|
||||
return @[];
|
||||
}
|
||||
NSMutableArray<FLEXIvarBox *> *boxedIvars = [NSMutableArray array];
|
||||
unsigned int ivarCount = 0;
|
||||
Ivar *ivarList = class_copyIvarList(class, &ivarCount);
|
||||
if (ivarList) {
|
||||
@@ -313,10 +406,11 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
return boxedIvars;
|
||||
}
|
||||
|
||||
+ (NSArray *)inheritedIvarsForClass:(Class)class
|
||||
/// Skips NSObject
|
||||
+ (NSArray<FLEXIvarBox *> *)inheritedIvarsForClass:(Class)class
|
||||
{
|
||||
NSMutableArray *inheritedIvars = [NSMutableArray array];
|
||||
while ((class = [class superclass])) {
|
||||
NSMutableArray<FLEXIvarBox *> *inheritedIvars = [NSMutableArray array];
|
||||
while ((class = [class superclass]) && class != [NSObject class]) {
|
||||
[inheritedIvars addObjectsFromArray:[self ivarsForClass:class]];
|
||||
}
|
||||
return inheritedIvars;
|
||||
@@ -324,14 +418,11 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
|
||||
- (void)updateFilteredIvars
|
||||
{
|
||||
NSArray *candidateIvars = self.ivars;
|
||||
if (self.includeInheritance) {
|
||||
candidateIvars = [candidateIvars arrayByAddingObjectsFromArray:self.inheritedIvars];
|
||||
}
|
||||
NSArray<FLEXIvarBox *> *candidateIvars = [self metadata:FLEXMetadataKindIvars forScope:self.scope];
|
||||
|
||||
NSArray *unsortedFilteredIvars = nil;
|
||||
NSArray<FLEXIvarBox *> *unsortedFilteredIvars = nil;
|
||||
if ([self.filterText length] > 0) {
|
||||
NSMutableArray *mutableUnsortedFilteredIvars = [NSMutableArray array];
|
||||
NSMutableArray<FLEXIvarBox *> *mutableUnsortedFilteredIvars = [NSMutableArray array];
|
||||
for (FLEXIvarBox *ivarBox in candidateIvars) {
|
||||
NSString *prettyName = [FLEXRuntimeUtility prettyNameForIvar:ivarBox.ivar];
|
||||
if ([prettyName rangeOfString:self.filterText options:NSCaseInsensitiveSearch].location != NSNotFound) {
|
||||
@@ -361,7 +452,9 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
id value = nil;
|
||||
if ([self canHaveInstanceState]) {
|
||||
FLEXIvarBox *ivarBox = self.filteredIvars[index];
|
||||
const FLEXTypeEncoding *encoding = ivar_getTypeEncoding(ivarBox.ivar);
|
||||
value = [FLEXRuntimeUtility valueForIvar:ivarBox.ivar onObject:self.object];
|
||||
value = [FLEXRuntimeUtility potentiallyUnwrapBoxedPointer:value type:encoding];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -373,12 +466,15 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
{
|
||||
Class class = [self.object class];
|
||||
self.methods = [[self class] methodsForClass:class];
|
||||
self.inheritedMethods = [[self class] inheritedMethodsForClass:class];
|
||||
self.methodsWithParent = [self.methods arrayByAddingObjectsFromArray:[[self class] methodsForClass:[class superclass]]];
|
||||
self.inheritedMethods = [self.methods arrayByAddingObjectsFromArray:[[self class] inheritedMethodsForClass:class]];
|
||||
self.NSObjectMethods = [[self class] methodsForClass:[NSObject class]];
|
||||
}
|
||||
|
||||
- (void)updateFilteredMethods
|
||||
{
|
||||
self.filteredMethods = [self filteredMethodsFromMethods:self.methods inheritedMethods:self.inheritedMethods areClassMethods:NO];
|
||||
NSArray<FLEXMethodBox *> *candidateMethods = [self metadata:FLEXMetadataKindMethods forScope:self.scope];
|
||||
self.filteredMethods = [self filteredMethodsFromMethods:candidateMethods areClassMethods:NO];
|
||||
}
|
||||
|
||||
- (void)updateClassMethods
|
||||
@@ -386,17 +482,24 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
const char *className = [NSStringFromClass([self.object class]) UTF8String];
|
||||
Class metaClass = objc_getMetaClass(className);
|
||||
self.classMethods = [[self class] methodsForClass:metaClass];
|
||||
self.inheritedClassMethods = [[self class] inheritedMethodsForClass:metaClass];
|
||||
self.classMethodsWithParent = [self.classMethods arrayByAddingObjectsFromArray:[[self class] methodsForClass:[metaClass superclass]]];
|
||||
self.inheritedClassMethods = [self.classMethods arrayByAddingObjectsFromArray:[[self class] inheritedMethodsForClass:metaClass]];
|
||||
self.NSObjectClassMethods = [[self class] methodsForClass:[NSObject class]];
|
||||
}
|
||||
|
||||
- (void)updateFilteredClassMethods
|
||||
{
|
||||
self.filteredClassMethods = [self filteredMethodsFromMethods:self.classMethods inheritedMethods:self.inheritedClassMethods areClassMethods:YES];
|
||||
NSArray<FLEXMethodBox *> *candidateMethods = [self metadata:FLEXMetadataKindClassMethods forScope:self.scope];
|
||||
self.filteredClassMethods = [self filteredMethodsFromMethods:candidateMethods areClassMethods:YES];
|
||||
}
|
||||
|
||||
+ (NSArray *)methodsForClass:(Class)class
|
||||
+ (NSArray<FLEXMethodBox *> *)methodsForClass:(Class)class
|
||||
{
|
||||
NSMutableArray *boxedMethods = [NSMutableArray array];
|
||||
if (!class) {
|
||||
return @[];
|
||||
}
|
||||
|
||||
NSMutableArray<FLEXMethodBox *> *boxedMethods = [NSMutableArray array];
|
||||
unsigned int methodCount = 0;
|
||||
Method *methodList = class_copyMethodList(class, &methodCount);
|
||||
if (methodList) {
|
||||
@@ -410,25 +513,22 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
return boxedMethods;
|
||||
}
|
||||
|
||||
+ (NSArray *)inheritedMethodsForClass:(Class)class
|
||||
/// Skips NSObject
|
||||
+ (NSArray<FLEXMethodBox *> *)inheritedMethodsForClass:(Class)class
|
||||
{
|
||||
NSMutableArray *inheritedMethods = [NSMutableArray array];
|
||||
while ((class = [class superclass])) {
|
||||
NSMutableArray<FLEXMethodBox *> *inheritedMethods = [NSMutableArray array];
|
||||
while ((class = [class superclass]) && class != [NSObject class]) {
|
||||
[inheritedMethods addObjectsFromArray:[self methodsForClass:class]];
|
||||
}
|
||||
return inheritedMethods;
|
||||
}
|
||||
|
||||
- (NSArray *)filteredMethodsFromMethods:(NSArray *)methods inheritedMethods:(NSArray *)inheritedMethods areClassMethods:(BOOL)areClassMethods
|
||||
- (NSArray<FLEXMethodBox *> *)filteredMethodsFromMethods:(NSArray<FLEXMethodBox *> *)methods areClassMethods:(BOOL)areClassMethods
|
||||
{
|
||||
NSArray *candidateMethods = methods;
|
||||
if (self.includeInheritance) {
|
||||
candidateMethods = [candidateMethods arrayByAddingObjectsFromArray:inheritedMethods];
|
||||
}
|
||||
|
||||
NSArray *unsortedFilteredMethods = nil;
|
||||
NSArray<FLEXMethodBox *> *candidateMethods = methods;
|
||||
NSArray<FLEXMethodBox *> *unsortedFilteredMethods = nil;
|
||||
if ([self.filterText length] > 0) {
|
||||
NSMutableArray *mutableUnsortedFilteredMethods = [NSMutableArray array];
|
||||
NSMutableArray<FLEXMethodBox *> *mutableUnsortedFilteredMethods = [NSMutableArray array];
|
||||
for (FLEXMethodBox *methodBox in candidateMethods) {
|
||||
NSString *prettyName = [FLEXRuntimeUtility prettyNameForMethod:methodBox.method isClassMethod:areClassMethods];
|
||||
if ([prettyName rangeOfString:self.filterText options:NSCaseInsensitiveSearch].location != NSNotFound) {
|
||||
@@ -440,7 +540,7 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
unsortedFilteredMethods = candidateMethods;
|
||||
}
|
||||
|
||||
NSArray *sortedFilteredMethods = [unsortedFilteredMethods sortedArrayUsingComparator:^NSComparisonResult(FLEXMethodBox *methodBox1, FLEXMethodBox *methodBox2) {
|
||||
NSArray<FLEXMethodBox *> *sortedFilteredMethods = [unsortedFilteredMethods sortedArrayUsingComparator:^NSComparisonResult(FLEXMethodBox *methodBox1, FLEXMethodBox *methodBox2) {
|
||||
NSString *name1 = NSStringFromSelector(method_getName(methodBox1.method));
|
||||
NSString *name2 = NSStringFromSelector(method_getName(methodBox2.method));
|
||||
return [name1 caseInsensitiveCompare:name2];
|
||||
@@ -464,9 +564,9 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
|
||||
#pragma mark - Superclasses
|
||||
|
||||
+ (NSArray *)superclassesForClass:(Class)class
|
||||
+ (NSArray<Class> *)superclassesForClass:(Class)class
|
||||
{
|
||||
NSMutableArray *superClasses = [NSMutableArray array];
|
||||
NSMutableArray<Class> *superClasses = [NSMutableArray array];
|
||||
while ((class = [class superclass])) {
|
||||
[superClasses addObject:class];
|
||||
}
|
||||
@@ -481,7 +581,7 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
- (void)updateFilteredSuperclasses
|
||||
{
|
||||
if ([self.filterText length] > 0) {
|
||||
NSMutableArray *filteredSuperclasses = [NSMutableArray array];
|
||||
NSMutableArray<Class> *filteredSuperclasses = [NSMutableArray array];
|
||||
for (Class superclass in self.superclasses) {
|
||||
if ([NSStringFromClass(superclass) rangeOfString:self.filterText options:NSCaseInsensitiveSearch].length > 0) {
|
||||
[filteredSuperclasses addObject:superclass];
|
||||
@@ -496,9 +596,9 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
|
||||
#pragma mark - Table View Data Helpers
|
||||
|
||||
- (NSArray *)possibleExplorerSections
|
||||
- (NSArray<NSNumber *> *)possibleExplorerSections
|
||||
{
|
||||
static NSArray *possibleSections = nil;
|
||||
static NSArray<NSNumber *> *possibleSections = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
possibleSections = @[@(FLEXObjectExplorerSectionDescription),
|
||||
@@ -513,9 +613,9 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
return possibleSections;
|
||||
}
|
||||
|
||||
- (NSArray *)visibleExplorerSections
|
||||
- (NSArray<NSNumber *> *)visibleExplorerSections
|
||||
{
|
||||
NSMutableArray *visibleSections = [NSMutableArray array];
|
||||
NSMutableArray<NSNumber *> *visibleSections = [NSMutableArray array];
|
||||
|
||||
for (NSNumber *possibleSection in [self possibleExplorerSections]) {
|
||||
FLEXObjectExplorerSection explorerSection = [possibleSection unsignedIntegerValue];
|
||||
@@ -736,34 +836,22 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
} break;
|
||||
|
||||
case FLEXObjectExplorerSectionProperties: {
|
||||
NSUInteger totalCount = [self.properties count];
|
||||
if (self.includeInheritance) {
|
||||
totalCount += [self.inheritedProperties count];
|
||||
}
|
||||
NSUInteger totalCount = [self totalCountOfMetadata:FLEXMetadataKindProperties forScope:self.scope];
|
||||
title = [self sectionTitleWithBaseName:@"Properties" totalCount:totalCount filteredCount:[self.filteredProperties count]];
|
||||
} break;
|
||||
|
||||
case FLEXObjectExplorerSectionIvars: {
|
||||
NSUInteger totalCount = [self.ivars count];
|
||||
if (self.includeInheritance) {
|
||||
totalCount += [self.inheritedIvars count];
|
||||
}
|
||||
NSUInteger totalCount = [self totalCountOfMetadata:FLEXMetadataKindIvars forScope:self.scope];
|
||||
title = [self sectionTitleWithBaseName:@"Ivars" totalCount:totalCount filteredCount:[self.filteredIvars count]];
|
||||
} break;
|
||||
|
||||
case FLEXObjectExplorerSectionMethods: {
|
||||
NSUInteger totalCount = [self.methods count];
|
||||
if (self.includeInheritance) {
|
||||
totalCount += [self.inheritedMethods count];
|
||||
}
|
||||
NSUInteger totalCount = [self totalCountOfMetadata:FLEXMetadataKindMethods forScope:self.scope];
|
||||
title = [self sectionTitleWithBaseName:@"Methods" totalCount:totalCount filteredCount:[self.filteredMethods count]];
|
||||
} break;
|
||||
|
||||
case FLEXObjectExplorerSectionClassMethods: {
|
||||
NSUInteger totalCount = [self.classMethods count];
|
||||
if (self.includeInheritance) {
|
||||
totalCount += [self.inheritedClassMethods count];
|
||||
}
|
||||
NSUInteger totalCount = [self totalCountOfMetadata:FLEXMetadataKindClassMethods forScope:self.scope];
|
||||
title = [self sectionTitleWithBaseName:@"Class Methods" totalCount:totalCount filteredCount:[self.filteredClassMethods count]];
|
||||
} break;
|
||||
|
||||
@@ -858,7 +946,8 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
FLEXObjectExplorerSection explorerSection = [self explorerSectionAtIndex:indexPath.section];
|
||||
|
||||
|
||||
BOOL isCustomSection = explorerSection == FLEXObjectExplorerSectionCustom;
|
||||
BOOL useDescriptionCell = explorerSection == FLEXObjectExplorerSectionDescription;
|
||||
NSString *cellIdentifier = useDescriptionCell ? kFLEXMultilineTableViewCellIdentifier : @"cell";
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
|
||||
@@ -874,7 +963,16 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
cell.detailTextLabel.textColor = [UIColor grayColor];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
UIView *customView;
|
||||
if (isCustomSection) {
|
||||
customView = [self customViewForRowCookie:[self customSectionRowCookieForVisibleRow:indexPath.row]];
|
||||
if (customView) {
|
||||
[cell.contentView addSubview:customView];
|
||||
}
|
||||
}
|
||||
|
||||
cell.textLabel.text = [self titleForRow:indexPath.row inExplorerSection:explorerSection];
|
||||
cell.detailTextLabel.text = [self subtitleForRow:indexPath.row inExplorerSection:explorerSection];
|
||||
cell.accessoryType = [self canDrillInToRow:indexPath.row inExplorerSection:explorerSection] ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
|
||||
@@ -891,7 +989,11 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{ NSFontAttributeName : [FLEXUtility defaultTableViewCellLabelFont] }];
|
||||
CGFloat preferredHeight = [FLEXMultilineTableViewCell preferredHeightWithAttributedText:attributedText inTableViewWidth:self.tableView.frame.size.width style:tableView.style showsAccessory:NO];
|
||||
height = MAX(height, preferredHeight);
|
||||
} else if (explorerSection == FLEXObjectExplorerSectionCustom) {
|
||||
id cookie = [self customSectionRowCookieForVisibleRow:indexPath.row];
|
||||
height = [self heightForCustomViewRowForRowCookie:cookie];
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
@@ -1020,6 +1122,16 @@ static const NSInteger kFLEXObjectExplorerScopeIncludeInheritanceIndex = 1;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UIView *)customViewForRowCookie:(id)rowCookie
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CGFloat)heightForCustomViewRowForRowCookie:(id)rowCookie
|
||||
{
|
||||
return self.tableView.rowHeight;
|
||||
}
|
||||
|
||||
- (BOOL)canHaveInstanceState
|
||||
{
|
||||
return YES;
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
|
||||
FLEXViewExplorerRowViewController,
|
||||
FLEXViewExplorerRowPreview
|
||||
FLEXViewExplorerRowPreview,
|
||||
FLEXViewExplorerRowViewControllerForAncestor
|
||||
};
|
||||
|
||||
@interface FLEXViewExplorerViewController ()
|
||||
@@ -46,6 +47,8 @@ typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
|
||||
|
||||
if ([FLEXUtility viewControllerForView:self.viewToExplore]) {
|
||||
[rowCookies addObject:@(FLEXViewExplorerRowViewController)];
|
||||
}else{
|
||||
[rowCookies addObject:@(FLEXViewExplorerRowViewControllerForAncestor)];
|
||||
}
|
||||
|
||||
[rowCookies addObject:@(FLEXViewExplorerRowPreview)];
|
||||
@@ -54,9 +57,9 @@ typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
|
||||
return rowCookies;
|
||||
}
|
||||
|
||||
- (NSArray *)shortcutPropertyNames
|
||||
- (NSArray<NSString *> *)shortcutPropertyNames
|
||||
{
|
||||
NSArray *propertyNames = @[@"frame", @"bounds", @"center", @"transform", @"backgroundColor", @"alpha", @"opaque", @"hidden", @"clipsToBounds", @"userInteractionEnabled", @"layer"];
|
||||
NSArray<NSString *> *propertyNames = @[@"frame", @"bounds", @"center", @"transform", @"backgroundColor", @"alpha", @"opaque", @"hidden", @"clipsToBounds", @"userInteractionEnabled", @"layer"];
|
||||
|
||||
if ([self.viewToExplore isKindOfClass:[UILabel class]]) {
|
||||
propertyNames = [@[@"text", @"font", @"textColor"] arrayByAddingObjectsFromArray:propertyNames];
|
||||
@@ -79,6 +82,10 @@ typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
|
||||
case FLEXViewExplorerRowPreview:
|
||||
title = @"Preview Image";
|
||||
break;
|
||||
|
||||
case FLEXViewExplorerRowViewControllerForAncestor:
|
||||
title = @"View Controller For Ancestor";
|
||||
break;
|
||||
}
|
||||
} else if ([rowCookie isKindOfClass:[NSString class]]) {
|
||||
objc_property_t property = [self viewPropertyForName:rowCookie];
|
||||
@@ -105,6 +112,10 @@ typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
|
||||
|
||||
case FLEXViewExplorerRowPreview:
|
||||
break;
|
||||
|
||||
case FLEXViewExplorerRowViewControllerForAncestor:
|
||||
subtitle = [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:[FLEXUtility viewControllerForAncestralView:self.viewToExplore]];
|
||||
break;
|
||||
}
|
||||
} else if ([rowCookie isKindOfClass:[NSString class]]) {
|
||||
objc_property_t property = [self viewPropertyForName:rowCookie];
|
||||
@@ -141,6 +152,10 @@ typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
|
||||
case FLEXViewExplorerRowPreview:
|
||||
drillInViewController = [[self class] imagePreviewViewControllerForView:self.viewToExplore];
|
||||
break;
|
||||
|
||||
case FLEXViewExplorerRowViewControllerForAncestor:
|
||||
drillInViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:[FLEXUtility viewControllerForAncestralView:self.viewToExplore]];
|
||||
break;
|
||||
}
|
||||
} else if ([rowCookie isKindOfClass:[NSString class]]) {
|
||||
objc_property_t property = [self viewPropertyForName:rowCookie];
|
||||
@@ -180,22 +195,22 @@ typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
|
||||
// We add these properties to the class at runtime if they haven't been added yet.
|
||||
// This way, we can use our property editor to access and change them.
|
||||
// The property attributes match the declared attributes in UIView.h
|
||||
NSDictionary *frameAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(CGRect)), kFLEXUtilityAttributeNonAtomic : @""};
|
||||
NSDictionary<NSString *, NSString *> *frameAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(CGRect)), kFLEXUtilityAttributeNonAtomic : @""};
|
||||
[FLEXRuntimeUtility tryAddPropertyWithName:"frame" attributes:frameAttributes toClass:[UIView class]];
|
||||
|
||||
NSDictionary *alphaAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(CGFloat)), kFLEXUtilityAttributeNonAtomic : @""};
|
||||
NSDictionary<NSString *, NSString *> *alphaAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(CGFloat)), kFLEXUtilityAttributeNonAtomic : @""};
|
||||
[FLEXRuntimeUtility tryAddPropertyWithName:"alpha" attributes:alphaAttributes toClass:[UIView class]];
|
||||
|
||||
NSDictionary *clipsAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @""};
|
||||
NSDictionary<NSString *, NSString *> *clipsAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @""};
|
||||
[FLEXRuntimeUtility tryAddPropertyWithName:"clipsToBounds" attributes:clipsAttributes toClass:[UIView class]];
|
||||
|
||||
NSDictionary *opaqueAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCustomGetter : @"isOpaque"};
|
||||
NSDictionary<NSString *, NSString *> *opaqueAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCustomGetter : @"isOpaque"};
|
||||
[FLEXRuntimeUtility tryAddPropertyWithName:"opaque" attributes:opaqueAttributes toClass:[UIView class]];
|
||||
|
||||
NSDictionary *hiddenAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCustomGetter : @"isHidden"};
|
||||
NSDictionary<NSString *, NSString *> *hiddenAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCustomGetter : @"isHidden"};
|
||||
[FLEXRuntimeUtility tryAddPropertyWithName:"hidden" attributes:hiddenAttributes toClass:[UIView class]];
|
||||
|
||||
NSDictionary *backgroundColorAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(FLEXEncodeClass(UIColor)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCopy : @""};
|
||||
NSDictionary<NSString *, NSString *> *backgroundColorAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(FLEXEncodeClass(UIColor)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCopy : @""};
|
||||
[FLEXRuntimeUtility tryAddPropertyWithName:"backgroundColor" attributes:backgroundColorAttributes toClass:[UIView class]];
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
|
||||
@interface FLEXExplorerToolbar : UIView
|
||||
|
||||
/// The items to be displayed in the toolbar. Defaults to:
|
||||
/// globalsItem, hierarchyItem, selectItem, moveItem, closeItem
|
||||
@property (nonatomic, copy) NSArray<FLEXToolbarItem *> *toolbarItems;
|
||||
|
||||
/// Toolbar item for selecting views.
|
||||
/// Users of the toolbar can configure the enabled/selected state and event targets/actions.
|
||||
@property (nonatomic, strong, readonly) FLEXToolbarItem *selectItem;
|
||||
+76
-30
@@ -22,12 +22,13 @@
|
||||
|
||||
@property (nonatomic, strong) UIImageView *dragHandleImageView;
|
||||
|
||||
@property (nonatomic, strong) NSArray *toolbarItems;
|
||||
|
||||
@property (nonatomic, strong) UIView *selectedViewDescriptionContainer;
|
||||
@property (nonatomic, strong) UIView *selectedViewDescriptionSafeAreaContainer;
|
||||
@property (nonatomic, strong) UIView *selectedViewColorIndicator;
|
||||
@property (nonatomic, strong) UILabel *selectedViewDescriptionLabel;
|
||||
|
||||
@property (nonatomic, strong,readwrite) UIView *backgroundView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXExplorerToolbar
|
||||
@@ -36,10 +37,12 @@
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
NSMutableArray *toolbarItems = [NSMutableArray array];
|
||||
|
||||
self.backgroundView = [[UIView alloc] init];
|
||||
self.backgroundView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.95];
|
||||
[self addSubview:self.backgroundView];
|
||||
|
||||
self.dragHandle = [[UIView alloc] init];
|
||||
self.dragHandle.backgroundColor = [FLEXToolbarItem defaultBackgroundColor];
|
||||
self.dragHandle.backgroundColor = [UIColor clearColor];
|
||||
[self addSubview:self.dragHandle];
|
||||
|
||||
UIImage *dragHandle = [FLEXResources dragHandle];
|
||||
@@ -48,56 +51,52 @@
|
||||
|
||||
UIImage *globalsIcon = [FLEXResources globeIcon];
|
||||
self.globalsItem = [FLEXToolbarItem toolbarItemWithTitle:@"menu" image:globalsIcon];
|
||||
[self addSubview:self.globalsItem];
|
||||
[toolbarItems addObject:self.globalsItem];
|
||||
|
||||
UIImage *listIcon = [FLEXResources listIcon];
|
||||
self.hierarchyItem = [FLEXToolbarItem toolbarItemWithTitle:@"views" image:listIcon];
|
||||
[self addSubview:self.hierarchyItem];
|
||||
[toolbarItems addObject:self.hierarchyItem];
|
||||
|
||||
UIImage *selectIcon = [FLEXResources selectIcon];
|
||||
self.selectItem = [FLEXToolbarItem toolbarItemWithTitle:@"select" image:selectIcon];
|
||||
[self addSubview:self.selectItem];
|
||||
[toolbarItems addObject:self.selectItem];
|
||||
|
||||
UIImage *moveIcon = [FLEXResources moveIcon];
|
||||
self.moveItem = [FLEXToolbarItem toolbarItemWithTitle:@"move" image:moveIcon];
|
||||
[self addSubview:self.moveItem];
|
||||
[toolbarItems addObject:self.moveItem];
|
||||
|
||||
UIImage *closeIcon = [FLEXResources closeIcon];
|
||||
self.closeItem = [FLEXToolbarItem toolbarItemWithTitle:@"close" image:closeIcon];
|
||||
[self addSubview:self.closeItem];
|
||||
[toolbarItems addObject:self.closeItem];
|
||||
|
||||
self.toolbarItems = toolbarItems;
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
|
||||
|
||||
self.selectedViewDescriptionContainer = [[UIView alloc] init];
|
||||
self.selectedViewDescriptionContainer.backgroundColor = [UIColor colorWithWhite:0.9 alpha:0.95];
|
||||
self.selectedViewDescriptionContainer.hidden = YES;
|
||||
[self addSubview:self.selectedViewDescriptionContainer];
|
||||
|
||||
self.selectedViewDescriptionSafeAreaContainer = [[UIView alloc] init];
|
||||
self.selectedViewDescriptionSafeAreaContainer.backgroundColor = [UIColor clearColor];
|
||||
[self.selectedViewDescriptionContainer addSubview:self.selectedViewDescriptionSafeAreaContainer];
|
||||
|
||||
self.selectedViewColorIndicator = [[UIView alloc] init];
|
||||
self.selectedViewColorIndicator.backgroundColor = [UIColor redColor];
|
||||
[self.selectedViewDescriptionContainer addSubview:self.selectedViewColorIndicator];
|
||||
[self.selectedViewDescriptionSafeAreaContainer addSubview:self.selectedViewColorIndicator];
|
||||
|
||||
self.selectedViewDescriptionLabel = [[UILabel alloc] init];
|
||||
self.selectedViewDescriptionLabel.backgroundColor = [UIColor clearColor];
|
||||
self.selectedViewDescriptionLabel.font = [[self class] descriptionLabelFont];
|
||||
[self.selectedViewDescriptionContainer addSubview:self.selectedViewDescriptionLabel];
|
||||
[self.selectedViewDescriptionSafeAreaContainer addSubview:self.selectedViewDescriptionLabel];
|
||||
|
||||
self.toolbarItems = @[_globalsItem, _hierarchyItem, _selectItem, _moveItem, _closeItem];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
|
||||
|
||||
CGRect safeArea = [self safeArea];
|
||||
// Drag Handle
|
||||
const CGFloat kToolbarItemHeight = [[self class] toolbarItemHeight];
|
||||
self.dragHandle.frame = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, [[self class] dragHandleWidth], kToolbarItemHeight);
|
||||
self.dragHandle.frame = CGRectMake(CGRectGetMinX(safeArea), CGRectGetMinY(safeArea), [[self class] dragHandleWidth], kToolbarItemHeight);
|
||||
CGRect dragHandleImageFrame = self.dragHandleImageView.frame;
|
||||
dragHandleImageFrame.origin.x = FLEXFloor((self.dragHandle.frame.size.width - dragHandleImageFrame.size.width) / 2.0);
|
||||
dragHandleImageFrame.origin.y = FLEXFloor((self.dragHandle.frame.size.height - dragHandleImageFrame.size.height) / 2.0);
|
||||
@@ -106,9 +105,9 @@
|
||||
|
||||
// Toolbar Items
|
||||
CGFloat originX = CGRectGetMaxX(self.dragHandle.frame);
|
||||
CGFloat originY = self.bounds.origin.y;
|
||||
CGFloat originY = CGRectGetMinY(safeArea);
|
||||
CGFloat height = kToolbarItemHeight;
|
||||
CGFloat width = FLEXFloor((CGRectGetMaxX(self.bounds) - originX) / [self.toolbarItems count]);
|
||||
CGFloat width = FLEXFloor((CGRectGetWidth(safeArea) - CGRectGetWidth(self.dragHandle.frame)) / [self.toolbarItems count]);
|
||||
for (UIView *toolbarItem in self.toolbarItems) {
|
||||
toolbarItem.frame = CGRectMake(originX, originY, width, height);
|
||||
originX = CGRectGetMaxX(toolbarItem.frame);
|
||||
@@ -117,8 +116,10 @@
|
||||
// Make sure the last toolbar item goes to the edge to account for any accumulated rounding effects.
|
||||
UIView *lastToolbarItem = [self.toolbarItems lastObject];
|
||||
CGRect lastToolbarItemFrame = lastToolbarItem.frame;
|
||||
lastToolbarItemFrame.size.width = CGRectGetMaxX(self.bounds) - lastToolbarItemFrame.origin.x;
|
||||
lastToolbarItemFrame.size.width = CGRectGetMaxX(safeArea) - lastToolbarItemFrame.origin.x;
|
||||
lastToolbarItem.frame = lastToolbarItemFrame;
|
||||
|
||||
self.backgroundView.frame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), kToolbarItemHeight);
|
||||
|
||||
const CGFloat kSelectedViewColorDiameter = [[self class] selectedViewColorIndicatorDiameter];
|
||||
const CGFloat kDescriptionLabelHeight = [[self class] descriptionLabelHeight];
|
||||
@@ -127,11 +128,19 @@
|
||||
const CGFloat kDescriptionContainerHeight = [[self class] descriptionContainerHeight];
|
||||
|
||||
CGRect descriptionContainerFrame = CGRectZero;
|
||||
descriptionContainerFrame.size.width = CGRectGetWidth(self.bounds);
|
||||
descriptionContainerFrame.size.height = kDescriptionContainerHeight;
|
||||
descriptionContainerFrame.origin.x = CGRectGetMinX(self.bounds);
|
||||
descriptionContainerFrame.origin.y = CGRectGetMaxY(self.bounds) - kDescriptionContainerHeight;
|
||||
descriptionContainerFrame.size.width = self.bounds.size.width;
|
||||
self.selectedViewDescriptionContainer.frame = descriptionContainerFrame;
|
||||
|
||||
|
||||
CGRect descriptionSafeAreaContainerFrame = CGRectZero;
|
||||
descriptionSafeAreaContainerFrame.size.width = CGRectGetWidth(safeArea);
|
||||
descriptionSafeAreaContainerFrame.size.height = kDescriptionContainerHeight;
|
||||
descriptionSafeAreaContainerFrame.origin.x = CGRectGetMinX(safeArea);
|
||||
descriptionSafeAreaContainerFrame.origin.y = CGRectGetMinY(safeArea);
|
||||
self.selectedViewDescriptionSafeAreaContainer.frame = descriptionSafeAreaContainerFrame;
|
||||
|
||||
// Selected View Color
|
||||
CGRect selectedViewColorFrame = CGRectZero;
|
||||
selectedViewColorFrame.size.width = kSelectedViewColorDiameter;
|
||||
@@ -150,10 +159,36 @@
|
||||
descriptionLabelFrame.size.width = CGRectGetMaxX(self.selectedViewDescriptionContainer.bounds) - kHorizontalPadding - descriptionOriginX;
|
||||
self.selectedViewDescriptionLabel.frame = descriptionLabelFrame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma mark - Setter Overrides
|
||||
|
||||
- (void)setToolbarItems:(NSArray<FLEXToolbarItem *> *)toolbarItems {
|
||||
if (_toolbarItems == toolbarItems) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove old toolbar items, if any
|
||||
for (FLEXToolbarItem *item in _toolbarItems) {
|
||||
[item removeFromSuperview];
|
||||
}
|
||||
|
||||
// Trim to 5 items if necessary
|
||||
if (toolbarItems.count > 5) {
|
||||
toolbarItems = [toolbarItems subarrayWithRange:NSMakeRange(0, 5)];
|
||||
}
|
||||
|
||||
for (FLEXToolbarItem *item in toolbarItems) {
|
||||
[self addSubview:item];
|
||||
}
|
||||
|
||||
_toolbarItems = toolbarItems.copy;
|
||||
|
||||
// Lay out new items
|
||||
[self setNeedsLayout];
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (void)setSelectedViewOverlayColor:(UIColor *)selectedViewOverlayColor
|
||||
{
|
||||
if (![_selectedViewOverlayColor isEqual:selectedViewOverlayColor]) {
|
||||
@@ -223,4 +258,15 @@
|
||||
return CGSizeMake(size.width, height);
|
||||
}
|
||||
|
||||
- (CGRect)safeArea
|
||||
{
|
||||
CGRect safeArea = self.bounds;
|
||||
#if FLEX_AT_LEAST_IOS11_SDK
|
||||
if (@available(iOS 11, *)) {
|
||||
safeArea = UIEdgeInsetsInsetRect(self.bounds, self.safeAreaInsets);
|
||||
}
|
||||
#endif
|
||||
return safeArea;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -12,6 +12,4 @@
|
||||
|
||||
+ (instancetype)toolbarItemWithTitle:(NSString *)title image:(UIImage *)image;
|
||||
|
||||
+ (UIColor *)defaultBackgroundColor;
|
||||
|
||||
@end
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
#pragma mark - Display Defaults
|
||||
|
||||
+ (NSDictionary *)titleAttributes
|
||||
+ (NSDictionary<NSString *, id> *)titleAttributes
|
||||
{
|
||||
return @{NSFontAttributeName : [FLEXUtility defaultFontOfSize:12.0]};
|
||||
}
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
+ (UIColor *)defaultBackgroundColor
|
||||
{
|
||||
return [UIColor colorWithWhite:1.0 alpha:0.95];
|
||||
return [UIColor clearColor];
|
||||
}
|
||||
|
||||
+ (CGFloat)topMargin
|
||||
@@ -0,0 +1,367 @@
|
||||
APPLE PUBLIC SOURCE LICENSE
|
||||
Version 2.0 - August 6, 2003
|
||||
|
||||
Please read this License carefully before downloading this software.
|
||||
By downloading or using this software, you are agreeing to be bound by
|
||||
the terms of this License. If you do not or cannot agree to the terms
|
||||
of this License, please do not download or use the software.
|
||||
|
||||
1. General; Definitions. This License applies to any program or other
|
||||
work which Apple Computer, Inc. ("Apple") makes publicly available and
|
||||
which contains a notice placed by Apple identifying such program or
|
||||
work as "Original Code" and stating that it is subject to the terms of
|
||||
this Apple Public Source License version 2.0 ("License"). As used in
|
||||
this License:
|
||||
|
||||
1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
|
||||
the grantor of rights, (i) claims of patents that are now or hereafter
|
||||
acquired, owned by or assigned to Apple and (ii) that cover subject
|
||||
matter contained in the Original Code, but only to the extent
|
||||
necessary to use, reproduce and/or distribute the Original Code
|
||||
without infringement; and (b) in the case where You are the grantor of
|
||||
rights, (i) claims of patents that are now or hereafter acquired,
|
||||
owned by or assigned to You and (ii) that cover subject matter in Your
|
||||
Modifications, taken alone or in combination with Original Code.
|
||||
|
||||
1.2 "Contributor" means any person or entity that creates or
|
||||
contributes to the creation of Modifications.
|
||||
|
||||
1.3 "Covered Code" means the Original Code, Modifications, the
|
||||
combination of Original Code and any Modifications, and/or any
|
||||
respective portions thereof.
|
||||
|
||||
1.4 "Externally Deploy" means: (a) to sublicense, distribute or
|
||||
otherwise make Covered Code available, directly or indirectly, to
|
||||
anyone other than You; and/or (b) to use Covered Code, alone or as
|
||||
part of a Larger Work, in any way to provide a service, including but
|
||||
not limited to delivery of content, through electronic communication
|
||||
with a client other than You.
|
||||
|
||||
1.5 "Larger Work" means a work which combines Covered Code or portions
|
||||
thereof with code not governed by the terms of this License.
|
||||
|
||||
1.6 "Modifications" mean any addition to, deletion from, and/or change
|
||||
to, the substance and/or structure of the Original Code, any previous
|
||||
Modifications, the combination of Original Code and any previous
|
||||
Modifications, and/or any respective portions thereof. When code is
|
||||
released as a series of files, a Modification is: (a) any addition to
|
||||
or deletion from the contents of a file containing Covered Code;
|
||||
and/or (b) any new file or other representation of computer program
|
||||
statements that contains any part of Covered Code.
|
||||
|
||||
1.7 "Original Code" means (a) the Source Code of a program or other
|
||||
work as originally made available by Apple under this License,
|
||||
including the Source Code of any updates or upgrades to such programs
|
||||
or works made available by Apple under this License, and that has been
|
||||
expressly identified by Apple as such in the header file(s) of such
|
||||
work; and (b) the object code compiled from such Source Code and
|
||||
originally made available by Apple under this License.
|
||||
|
||||
1.8 "Source Code" means the human readable form of a program or other
|
||||
work that is suitable for making modifications to it, including all
|
||||
modules it contains, plus any associated interface definition files,
|
||||
scripts used to control compilation and installation of an executable
|
||||
(object code).
|
||||
|
||||
1.9 "You" or "Your" means an individual or a legal entity exercising
|
||||
rights under this License. For legal entities, "You" or "Your"
|
||||
includes any entity which controls, is controlled by, or is under
|
||||
common control with, You, where "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of fifty percent
|
||||
(50%) or more of the outstanding shares or beneficial ownership of
|
||||
such entity.
|
||||
|
||||
2. Permitted Uses; Conditions & Restrictions. Subject to the terms
|
||||
and conditions of this License, Apple hereby grants You, effective on
|
||||
the date You accept this License and download the Original Code, a
|
||||
world-wide, royalty-free, non-exclusive license, to the extent of
|
||||
Apple's Applicable Patent Rights and copyrights covering the Original
|
||||
Code, to do the following:
|
||||
|
||||
2.1 Unmodified Code. You may use, reproduce, display, perform,
|
||||
internally distribute within Your organization, and Externally Deploy
|
||||
verbatim, unmodified copies of the Original Code, for commercial or
|
||||
non-commercial purposes, provided that in each instance:
|
||||
|
||||
(a) You must retain and reproduce in all copies of Original Code the
|
||||
copyright and other proprietary notices and disclaimers of Apple as
|
||||
they appear in the Original Code, and keep intact all notices in the
|
||||
Original Code that refer to this License; and
|
||||
|
||||
(b) You must include a copy of this License with every copy of Source
|
||||
Code of Covered Code and documentation You distribute or Externally
|
||||
Deploy, and You may not offer or impose any terms on such Source Code
|
||||
that alter or restrict this License or the recipients' rights
|
||||
hereunder, except as permitted under Section 6.
|
||||
|
||||
2.2 Modified Code. You may modify Covered Code and use, reproduce,
|
||||
display, perform, internally distribute within Your organization, and
|
||||
Externally Deploy Your Modifications and Covered Code, for commercial
|
||||
or non-commercial purposes, provided that in each instance You also
|
||||
meet all of these conditions:
|
||||
|
||||
(a) You must satisfy all the conditions of Section 2.1 with respect to
|
||||
the Source Code of the Covered Code;
|
||||
|
||||
(b) You must duplicate, to the extent it does not already exist, the
|
||||
notice in Exhibit A in each file of the Source Code of all Your
|
||||
Modifications, and cause the modified files to carry prominent notices
|
||||
stating that You changed the files and the date of any change; and
|
||||
|
||||
(c) If You Externally Deploy Your Modifications, You must make
|
||||
Source Code of all Your Externally Deployed Modifications either
|
||||
available to those to whom You have Externally Deployed Your
|
||||
Modifications, or publicly available. Source Code of Your Externally
|
||||
Deployed Modifications must be released under the terms set forth in
|
||||
this License, including the license grants set forth in Section 3
|
||||
below, for as long as you Externally Deploy the Covered Code or twelve
|
||||
(12) months from the date of initial External Deployment, whichever is
|
||||
longer. You should preferably distribute the Source Code of Your
|
||||
Externally Deployed Modifications electronically (e.g. download from a
|
||||
web site).
|
||||
|
||||
2.3 Distribution of Executable Versions. In addition, if You
|
||||
Externally Deploy Covered Code (Original Code and/or Modifications) in
|
||||
object code, executable form only, You must include a prominent
|
||||
notice, in the code itself as well as in related documentation,
|
||||
stating that Source Code of the Covered Code is available under the
|
||||
terms of this License with information on how and where to obtain such
|
||||
Source Code.
|
||||
|
||||
2.4 Third Party Rights. You expressly acknowledge and agree that
|
||||
although Apple and each Contributor grants the licenses to their
|
||||
respective portions of the Covered Code set forth herein, no
|
||||
assurances are provided by Apple or any Contributor that the Covered
|
||||
Code does not infringe the patent or other intellectual property
|
||||
rights of any other entity. Apple and each Contributor disclaim any
|
||||
liability to You for claims brought by any other entity based on
|
||||
infringement of intellectual property rights or otherwise. As a
|
||||
condition to exercising the rights and licenses granted hereunder, You
|
||||
hereby assume sole responsibility to secure any other intellectual
|
||||
property rights needed, if any. For example, if a third party patent
|
||||
license is required to allow You to distribute the Covered Code, it is
|
||||
Your responsibility to acquire that license before distributing the
|
||||
Covered Code.
|
||||
|
||||
3. Your Grants. In consideration of, and as a condition to, the
|
||||
licenses granted to You under this License, You hereby grant to any
|
||||
person or entity receiving or distributing Covered Code under this
|
||||
License a non-exclusive, royalty-free, perpetual, irrevocable license,
|
||||
under Your Applicable Patent Rights and other intellectual property
|
||||
rights (other than patent) owned or controlled by You, to use,
|
||||
reproduce, display, perform, modify, sublicense, distribute and
|
||||
Externally Deploy Your Modifications of the same scope and extent as
|
||||
Apple's licenses under Sections 2.1 and 2.2 above.
|
||||
|
||||
4. Larger Works. You may create a Larger Work by combining Covered
|
||||
Code with other code not governed by the terms of this License and
|
||||
distribute the Larger Work as a single product. In each such instance,
|
||||
You must make sure the requirements of this License are fulfilled for
|
||||
the Covered Code or any portion thereof.
|
||||
|
||||
5. Limitations on Patent License. Except as expressly stated in
|
||||
Section 2, no other patent rights, express or implied, are granted by
|
||||
Apple herein. Modifications and/or Larger Works may require additional
|
||||
patent licenses from Apple which Apple may grant in its sole
|
||||
discretion.
|
||||
|
||||
6. Additional Terms. You may choose to offer, and to charge a fee for,
|
||||
warranty, support, indemnity or liability obligations and/or other
|
||||
rights consistent with the scope of the license granted herein
|
||||
("Additional Terms") to one or more recipients of Covered Code.
|
||||
However, You may do so only on Your own behalf and as Your sole
|
||||
responsibility, and not on behalf of Apple or any Contributor. You
|
||||
must obtain the recipient's agreement that any such Additional Terms
|
||||
are offered by You alone, and You hereby agree to indemnify, defend
|
||||
and hold Apple and every Contributor harmless for any liability
|
||||
incurred by or claims asserted against Apple or such Contributor by
|
||||
reason of any such Additional Terms.
|
||||
|
||||
7. Versions of the License. Apple may publish revised and/or new
|
||||
versions of this License from time to time. Each version will be given
|
||||
a distinguishing version number. Once Original Code has been published
|
||||
under a particular version of this License, You may continue to use it
|
||||
under the terms of that version. You may also choose to use such
|
||||
Original Code under the terms of any subsequent version of this
|
||||
License published by Apple. No one other than Apple has the right to
|
||||
modify the terms applicable to Covered Code created under this
|
||||
License.
|
||||
|
||||
8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
|
||||
part pre-release, untested, or not fully tested works. The Covered
|
||||
Code may contain errors that could cause failures or loss of data, and
|
||||
may be incomplete or contain inaccuracies. You expressly acknowledge
|
||||
and agree that use of the Covered Code, or any portion thereof, is at
|
||||
Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
|
||||
WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
|
||||
APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
|
||||
PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
|
||||
ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
|
||||
NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
|
||||
MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
|
||||
PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
|
||||
PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
|
||||
INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
|
||||
FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
|
||||
THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
|
||||
ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
|
||||
ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
|
||||
AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
|
||||
You acknowledge that the Covered Code is not intended for use in the
|
||||
operation of nuclear facilities, aircraft navigation, communication
|
||||
systems, or air traffic control machines in which case the failure of
|
||||
the Covered Code could lead to death, personal injury, or severe
|
||||
physical or environmental damage.
|
||||
|
||||
9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
|
||||
EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
|
||||
TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
|
||||
ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
|
||||
TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
|
||||
APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
|
||||
REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
|
||||
INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
|
||||
TO YOU. In no event shall Apple's total liability to You for all
|
||||
damages (other than as may be required by applicable law) under this
|
||||
License exceed the amount of fifty dollars ($50.00).
|
||||
|
||||
10. Trademarks. This License does not grant any rights to use the
|
||||
trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
|
||||
"QuickTime", "QuickTime Streaming Server" or any other trademarks,
|
||||
service marks, logos or trade names belonging to Apple (collectively
|
||||
"Apple Marks") or to any trademark, service mark, logo or trade name
|
||||
belonging to any Contributor. You agree not to use any Apple Marks in
|
||||
or as part of the name of products derived from the Original Code or
|
||||
to endorse or promote products derived from the Original Code other
|
||||
than as expressly permitted by and in strict compliance at all times
|
||||
with Apple's third party trademark usage guidelines which are posted
|
||||
at http://www.apple.com/legal/guidelinesfor3rdparties.html.
|
||||
|
||||
11. Ownership. Subject to the licenses granted under this License,
|
||||
each Contributor retains all rights, title and interest in and to any
|
||||
Modifications made by such Contributor. Apple retains all rights,
|
||||
title and interest in and to the Original Code and any Modifications
|
||||
made by or on behalf of Apple ("Apple Modifications"), and such Apple
|
||||
Modifications will not be automatically subject to this License. Apple
|
||||
may, at its sole discretion, choose to license such Apple
|
||||
Modifications under this License, or on different terms from those
|
||||
contained in this License or may choose not to license them at all.
|
||||
|
||||
12. Termination.
|
||||
|
||||
12.1 Termination. This License and the rights granted hereunder will
|
||||
terminate:
|
||||
|
||||
(a) automatically without notice from Apple if You fail to comply with
|
||||
any term(s) of this License and fail to cure such breach within 30
|
||||
days of becoming aware of such breach;
|
||||
|
||||
(b) immediately in the event of the circumstances described in Section
|
||||
13.5(b); or
|
||||
|
||||
(c) automatically without notice from Apple if You, at any time during
|
||||
the term of this License, commence an action for patent infringement
|
||||
against Apple; provided that Apple did not first commence
|
||||
an action for patent infringement against You in that instance.
|
||||
|
||||
12.2 Effect of Termination. Upon termination, You agree to immediately
|
||||
stop any further use, reproduction, modification, sublicensing and
|
||||
distribution of the Covered Code. All sublicenses to the Covered Code
|
||||
which have been properly granted prior to termination shall survive
|
||||
any termination of this License. Provisions which, by their nature,
|
||||
should remain in effect beyond the termination of this License shall
|
||||
survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
|
||||
12.2 and 13. No party will be liable to any other for compensation,
|
||||
indemnity or damages of any sort solely as a result of terminating
|
||||
this License in accordance with its terms, and termination of this
|
||||
License will be without prejudice to any other right or remedy of
|
||||
any party.
|
||||
|
||||
13. Miscellaneous.
|
||||
|
||||
13.1 Government End Users. The Covered Code is a "commercial item" as
|
||||
defined in FAR 2.101. Government software and technical data rights in
|
||||
the Covered Code include only those rights customarily provided to the
|
||||
public as defined in this License. This customary commercial license
|
||||
in technical data and software is provided in accordance with FAR
|
||||
12.211 (Technical Data) and 12.212 (Computer Software) and, for
|
||||
Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
|
||||
Commercial Items) and 227.7202-3 (Rights in Commercial Computer
|
||||
Software or Computer Software Documentation). Accordingly, all U.S.
|
||||
Government End Users acquire Covered Code with only those rights set
|
||||
forth herein.
|
||||
|
||||
13.2 Relationship of Parties. This License will not be construed as
|
||||
creating an agency, partnership, joint venture or any other form of
|
||||
legal association between or among You, Apple or any Contributor, and
|
||||
You will not represent to the contrary, whether expressly, by
|
||||
implication, appearance or otherwise.
|
||||
|
||||
13.3 Independent Development. Nothing in this License will impair
|
||||
Apple's right to acquire, license, develop, have others develop for
|
||||
it, market and/or distribute technology or products that perform the
|
||||
same or similar functions as, or otherwise compete with,
|
||||
Modifications, Larger Works, technology or products that You may
|
||||
develop, produce, market or distribute.
|
||||
|
||||
13.4 Waiver; Construction. Failure by Apple or any Contributor to
|
||||
enforce any provision of this License will not be deemed a waiver of
|
||||
future enforcement of that or any other provision. Any law or
|
||||
regulation which provides that the language of a contract shall be
|
||||
construed against the drafter will not apply to this License.
|
||||
|
||||
13.5 Severability. (a) If for any reason a court of competent
|
||||
jurisdiction finds any provision of this License, or portion thereof,
|
||||
to be unenforceable, that provision of the License will be enforced to
|
||||
the maximum extent permissible so as to effect the economic benefits
|
||||
and intent of the parties, and the remainder of this License will
|
||||
continue in full force and effect. (b) Notwithstanding the foregoing,
|
||||
if applicable law prohibits or restricts You from fully and/or
|
||||
specifically complying with Sections 2 and/or 3 or prevents the
|
||||
enforceability of either of those Sections, this License will
|
||||
immediately terminate and You must immediately discontinue any use of
|
||||
the Covered Code and destroy all copies of it that are in your
|
||||
possession or control.
|
||||
|
||||
13.6 Dispute Resolution. Any litigation or other dispute resolution
|
||||
between You and Apple relating to this License shall take place in the
|
||||
Northern District of California, and You and Apple hereby consent to
|
||||
the personal jurisdiction of, and venue in, the state and federal
|
||||
courts within that District with respect to this License. The
|
||||
application of the United Nations Convention on Contracts for the
|
||||
International Sale of Goods is expressly excluded.
|
||||
|
||||
13.7 Entire Agreement; Governing Law. This License constitutes the
|
||||
entire agreement between the parties with respect to the subject
|
||||
matter hereof. This License shall be governed by the laws of the
|
||||
United States and the State of California, except that body of
|
||||
California law concerning conflicts of law.
|
||||
|
||||
Where You are located in the province of Quebec, Canada, the following
|
||||
clause applies: The parties hereby confirm that they have requested
|
||||
that this License and all related documents be drafted in English. Les
|
||||
parties ont exige que le present contrat et tous les documents
|
||||
connexes soient rediges en anglais.
|
||||
|
||||
EXHIBIT A.
|
||||
|
||||
"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
|
||||
Reserved.
|
||||
|
||||
This file contains Original Code and/or Modifications of Original Code
|
||||
as defined in and that are subject to the Apple Public Source License
|
||||
Version 2.0 (the 'License'). You may not use this file except in
|
||||
compliance with the License. Please obtain a copy of the License at
|
||||
http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
file.
|
||||
|
||||
The Original Code and all software distributed under the License are
|
||||
distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
Please see the License for the specific language governing rights and
|
||||
limitations under the License."
|
||||
@@ -20,16 +20,9 @@ typedef struct {
|
||||
|
||||
@implementation FLEXHeapEnumerator
|
||||
|
||||
static kern_return_t memory_reader(task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory)
|
||||
{
|
||||
*local_memory = (void *)remote_address;
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
static void range_callback(task_t task, void *context, unsigned type, vm_range_t *ranges, unsigned rangeCount)
|
||||
{
|
||||
flex_object_enumeration_block_t block = (__bridge flex_object_enumeration_block_t)context;
|
||||
if (!block) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -46,11 +39,17 @@ static void range_callback(task_t task, void *context, unsigned type, vm_range_t
|
||||
#endif
|
||||
// If the class pointer matches one in our set of class pointers from the runtime, then we should have an object.
|
||||
if (CFSetContainsValue(registeredClasses, (__bridge const void *)(tryClass))) {
|
||||
block((__bridge id)tryObject, tryClass);
|
||||
(*(flex_object_enumeration_block_t __unsafe_unretained *)context)((__bridge id)tryObject, tryClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static kern_return_t reader(__unused task_t remote_task, vm_address_t remote_address, __unused vm_size_t size, void **local_memory)
|
||||
{
|
||||
*local_memory = (void *)remote_address;
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
+ (void)enumerateLiveObjectsUsingBlock:(flex_object_enumeration_block_t)block
|
||||
{
|
||||
if (!block) {
|
||||
@@ -60,18 +59,58 @@ static void range_callback(task_t task, void *context, unsigned type, vm_range_t
|
||||
// Refresh the class list on every call in case classes are added to the runtime.
|
||||
[self updateRegisteredClasses];
|
||||
|
||||
// For another exmple of enumerating through malloc ranges (which helped my understanding of the api) see:
|
||||
// Inspired by:
|
||||
// http://llvm.org/svn/llvm-project/lldb/tags/RELEASE_34/final/examples/darwin/heap_find/heap/heap_find.cpp
|
||||
// Also https://gist.github.com/samdmarshall/17f4e66b5e2e579fd396
|
||||
// https://gist.github.com/samdmarshall/17f4e66b5e2e579fd396
|
||||
|
||||
vm_address_t *zones = NULL;
|
||||
unsigned int zoneCount = 0;
|
||||
kern_return_t result = malloc_get_all_zones(mach_task_self(), &memory_reader, &zones, &zoneCount);
|
||||
kern_return_t result = malloc_get_all_zones(TASK_NULL, reader, &zones, &zoneCount);
|
||||
|
||||
if (result == KERN_SUCCESS) {
|
||||
for (unsigned int i = 0; i < zoneCount; i++) {
|
||||
malloc_zone_t *zone = (malloc_zone_t *)zones[i];
|
||||
if (zone->introspect && zone->introspect->enumerator) {
|
||||
zone->introspect->enumerator(mach_task_self(), (__bridge void *)(block), MALLOC_PTR_IN_USE_RANGE_TYPE, zones[i], &memory_reader, &range_callback);
|
||||
malloc_introspection_t *introspection = zone->introspect;
|
||||
NSString *zoneName = @(zone->zone_name);
|
||||
|
||||
if (![zoneName isEqualToString:@"DefaultMallocZone"] || !introspection) {
|
||||
continue;
|
||||
}
|
||||
|
||||
void (*lock_zone)(malloc_zone_t *zone) = introspection->force_lock;
|
||||
void (*unlock_zone)(malloc_zone_t *zone) = introspection->force_unlock;
|
||||
|
||||
// Callback has to unlock the zone so we freely allocate memory inside the given block
|
||||
flex_object_enumeration_block_t callback = ^(__unsafe_unretained id object, __unsafe_unretained Class actualClass) {
|
||||
unlock_zone(zone);
|
||||
block(object, actualClass);
|
||||
lock_zone(zone);
|
||||
};
|
||||
|
||||
// The largest realistic memory address varies by platform.
|
||||
// Only 48 bits are used by 64 bit machines while
|
||||
// 32 bit machines use all bits.
|
||||
#if __arm64__
|
||||
static uintptr_t MAX_REALISTIC_ADDRESS = 0xFFFFFFFFFFFF;
|
||||
#else
|
||||
static uintptr_t MAX_REALISTIC_ADDRESS = INT_MAX;
|
||||
#endif
|
||||
|
||||
// There is little documentation on when and why
|
||||
// any of these function pointers might be NULL
|
||||
// or garbage, so we resort to checking for NULL
|
||||
// and impossible memory addresses at least
|
||||
if (lock_zone && unlock_zone &&
|
||||
introspection->enumerator &&
|
||||
(uintptr_t)lock_zone < MAX_REALISTIC_ADDRESS &&
|
||||
(uintptr_t)unlock_zone < MAX_REALISTIC_ADDRESS) {
|
||||
lock_zone(zone);
|
||||
introspection->enumerator(TASK_NULL, (void *)&callback, MALLOC_PTR_IN_USE_RANGE_TYPE, (vm_address_t)zone, reader, &range_callback);
|
||||
unlock_zone(zone);
|
||||
}
|
||||
|
||||
// Only one zone to enumerate
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,12 +57,12 @@
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
NSDictionary *keyMappings = @{ UIKeyInputUpArrow : @"↑",
|
||||
UIKeyInputDownArrow : @"↓",
|
||||
UIKeyInputLeftArrow : @"←",
|
||||
UIKeyInputRightArrow : @"→",
|
||||
UIKeyInputEscape : @"␛",
|
||||
@" " : @"␠"};
|
||||
NSDictionary<NSString *, NSString *> *keyMappings = @{ UIKeyInputUpArrow : @"↑",
|
||||
UIKeyInputDownArrow : @"↓",
|
||||
UIKeyInputLeftArrow : @"←",
|
||||
UIKeyInputRightArrow : @"→",
|
||||
UIKeyInputEscape : @"␛",
|
||||
@" " : @"␠"};
|
||||
|
||||
NSString *prettyKey = nil;
|
||||
if (self.key && keyMappings[self.key]) {
|
||||
@@ -113,7 +113,7 @@
|
||||
|
||||
@interface FLEXKeyboardShortcutManager ()
|
||||
|
||||
@property (nonatomic, strong) NSMutableDictionary *actionsForKeyInputs;
|
||||
@property (nonatomic, strong) NSMutableDictionary<FLEXKeyInput *, dispatch_block_t> *actionsForKeyInputs;
|
||||
|
||||
@property (nonatomic, assign, getter=isPressingShift) BOOL pressingShift;
|
||||
@property (nonatomic, assign, getter=isPressingCommand) BOOL pressingCommand;
|
||||
@@ -147,43 +147,49 @@
|
||||
|
||||
[FLEXUtility replaceImplementationOfKnownSelector:originalKeyEventSelector onClass:[UIApplication class] withBlock:handleKeyUIEventSwizzleBlock swizzledSelector:swizzledKeyEventSelector];
|
||||
|
||||
SEL originalSendEventSelector = NSSelectorFromString(@"sendEvent:");
|
||||
SEL swizzledSendEventSelector = [FLEXUtility swizzledSelectorForSelector:originalSendEventSelector];
|
||||
|
||||
void (^sendEventSwizzleBlock)(UIApplication *, UIEvent *) = ^(UIApplication *slf, UIEvent *event) {
|
||||
if (event.type == UIEventTypeTouches) {
|
||||
FLEXKeyboardShortcutManager *keyboardManager = [FLEXKeyboardShortcutManager sharedManager];
|
||||
NSInteger pressureLevel = 0;
|
||||
if (keyboardManager.isPressingShift) {
|
||||
pressureLevel++;
|
||||
}
|
||||
if (keyboardManager.isPressingCommand) {
|
||||
pressureLevel++;
|
||||
}
|
||||
if (keyboardManager.isPressingControl) {
|
||||
pressureLevel++;
|
||||
}
|
||||
if (pressureLevel > 0) {
|
||||
for (UITouch *touch in [event allTouches]) {
|
||||
double adjustedPressureLevel = pressureLevel * 20 * touch.maximumPossibleForce;
|
||||
[touch setValue:@(adjustedPressureLevel) forKey:@"_pressure"];
|
||||
if ([[UITouch class] instancesRespondToSelector:@selector(maximumPossibleForce)]) {
|
||||
SEL originalSendEventSelector = NSSelectorFromString(@"sendEvent:");
|
||||
SEL swizzledSendEventSelector = [FLEXUtility swizzledSelectorForSelector:originalSendEventSelector];
|
||||
|
||||
void (^sendEventSwizzleBlock)(UIApplication *, UIEvent *) = ^(UIApplication *slf, UIEvent *event) {
|
||||
if (event.type == UIEventTypeTouches) {
|
||||
FLEXKeyboardShortcutManager *keyboardManager = [FLEXKeyboardShortcutManager sharedManager];
|
||||
NSInteger pressureLevel = 0;
|
||||
if (keyboardManager.isPressingShift) {
|
||||
pressureLevel++;
|
||||
}
|
||||
if (keyboardManager.isPressingCommand) {
|
||||
pressureLevel++;
|
||||
}
|
||||
if (keyboardManager.isPressingControl) {
|
||||
pressureLevel++;
|
||||
}
|
||||
if (pressureLevel > 0) {
|
||||
#if FLEX_AT_LEAST_IOS11_SDK
|
||||
if (@available(iOS 9.0, *)) {
|
||||
for (UITouch *touch in [event allTouches]) {
|
||||
double adjustedPressureLevel = pressureLevel * 20 * touch.maximumPossibleForce;
|
||||
[touch setValue:@(adjustedPressureLevel) forKey:@"_pressure"];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
((void(*)(id, SEL, id))objc_msgSend)(slf, swizzledSendEventSelector, event);
|
||||
};
|
||||
|
||||
((void(*)(id, SEL, id))objc_msgSend)(slf, swizzledSendEventSelector, event);
|
||||
};
|
||||
|
||||
[FLEXUtility replaceImplementationOfKnownSelector:originalSendEventSelector onClass:[UIApplication class] withBlock:sendEventSwizzleBlock swizzledSelector:swizzledSendEventSelector];
|
||||
|
||||
SEL originalSupportsTouchPressureSelector = NSSelectorFromString(@"_supportsForceTouch");
|
||||
SEL swizzledSupportsTouchPressureSelector = [FLEXUtility swizzledSelectorForSelector:originalSupportsTouchPressureSelector];
|
||||
|
||||
BOOL (^supportsTouchPressureSwizzleBlock)(UIDevice *) = ^BOOL(UIDevice *slf) {
|
||||
return YES;
|
||||
};
|
||||
|
||||
[FLEXUtility replaceImplementationOfKnownSelector:originalSupportsTouchPressureSelector onClass:[UIDevice class] withBlock:supportsTouchPressureSwizzleBlock swizzledSelector:swizzledSupportsTouchPressureSelector];
|
||||
[FLEXUtility replaceImplementationOfKnownSelector:originalSendEventSelector onClass:[UIApplication class] withBlock:sendEventSwizzleBlock swizzledSelector:swizzledSendEventSelector];
|
||||
|
||||
SEL originalSupportsTouchPressureSelector = NSSelectorFromString(@"_supportsForceTouch");
|
||||
SEL swizzledSupportsTouchPressureSelector = [FLEXUtility swizzledSelectorForSelector:originalSupportsTouchPressureSelector];
|
||||
|
||||
BOOL (^supportsTouchPressureSwizzleBlock)(UIDevice *) = ^BOOL(UIDevice *slf) {
|
||||
return YES;
|
||||
};
|
||||
|
||||
[FLEXUtility replaceImplementationOfKnownSelector:originalSupportsTouchPressureSelector onClass:[UIDevice class] withBlock:supportsTouchPressureSwizzleBlock swizzledSelector:swizzledSupportsTouchPressureSelector];
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
@@ -218,7 +224,6 @@ static const long kFLEXCommandKeyCode = 0xe3;
|
||||
NSString *unmodifiedInput = nil;
|
||||
UIKeyModifierFlags flags = 0;
|
||||
BOOL isKeyDown = NO;
|
||||
long keyCode = 0;
|
||||
|
||||
if ([event respondsToSelector:@selector(_modifiedInput)]) {
|
||||
modifiedInput = [event _modifiedInput];
|
||||
@@ -236,17 +241,14 @@ static const long kFLEXCommandKeyCode = 0xe3;
|
||||
isKeyDown = [event _isKeyDown];
|
||||
}
|
||||
|
||||
if ([event respondsToSelector:@selector(_keyCode)]) {
|
||||
keyCode = [event _keyCode];
|
||||
}
|
||||
|
||||
BOOL interactionEnabled = ![[UIApplication sharedApplication] isIgnoringInteractionEvents];
|
||||
|
||||
BOOL hasFirstResponder = NO;
|
||||
if (isKeyDown && [modifiedInput length] > 0 && interactionEnabled) {
|
||||
UIResponder *firstResponder = nil;
|
||||
for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
|
||||
for (UIWindow *window in [FLEXUtility allWindows]) {
|
||||
firstResponder = [window valueForKey:@"firstResponder"];
|
||||
if (firstResponder) {
|
||||
hasFirstResponder = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -262,7 +264,7 @@ static const long kFLEXCommandKeyCode = 0xe3;
|
||||
dispatch_block_t actionBlock = self.actionsForKeyInputs[exactMatch];
|
||||
|
||||
if (!actionBlock) {
|
||||
FLEXKeyInput *shiftMatch = [FLEXKeyInput keyInputForKey:modifiedInput flags:flags&(!UIKeyModifierShift)];
|
||||
FLEXKeyInput *shiftMatch = [FLEXKeyInput keyInputForKey:modifiedInput flags:flags&(~UIKeyModifierShift)];
|
||||
actionBlock = self.actionsForKeyInputs[shiftMatch];
|
||||
}
|
||||
|
||||
@@ -277,19 +279,24 @@ static const long kFLEXCommandKeyCode = 0xe3;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyCode == kFLEXControlKeyCode) {
|
||||
self.pressingControl = isKeyDown;
|
||||
} else if (keyCode == kFLEXCommandKeyCode) {
|
||||
self.pressingCommand = isKeyDown;
|
||||
} else if (keyCode == kFLEXShiftKeyCode) {
|
||||
self.pressingShift = isKeyDown;
|
||||
// Calling _keyCode on events from the simulator keyboard will crash.
|
||||
// It is only safe to call _keyCode when there's not an active responder.
|
||||
if (!hasFirstResponder && [event respondsToSelector:@selector(_keyCode)]) {
|
||||
long keyCode = [event _keyCode];
|
||||
if (keyCode == kFLEXControlKeyCode) {
|
||||
self.pressingControl = isKeyDown;
|
||||
} else if (keyCode == kFLEXCommandKeyCode) {
|
||||
self.pressingCommand = isKeyDown;
|
||||
} else if (keyCode == kFLEXShiftKeyCode) {
|
||||
self.pressingShift = isKeyDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)keyboardShortcutsDescription
|
||||
{
|
||||
NSMutableString *description = [NSMutableString string];
|
||||
NSArray *keyInputs = [[self.actionsForKeyInputs allKeys] sortedArrayUsingComparator:^NSComparisonResult(FLEXKeyInput *_Nonnull input1, FLEXKeyInput *_Nonnull input2) {
|
||||
NSArray<FLEXKeyInput *> *keyInputs = [[self.actionsForKeyInputs allKeys] sortedArrayUsingComparator:^NSComparisonResult(FLEXKeyInput *_Nonnull input1, FLEXKeyInput *_Nonnull input2) {
|
||||
return [input1.key caseInsensitiveCompare:input2.key];
|
||||
}];
|
||||
for (FLEXKeyInput *keyInput in keyInputs) {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// FLEXObjcInternal.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner Bennett on 11/1/18.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @brief Assumes memory is valid and readable.
|
||||
/// @discussion objc-internal.h, objc-private.h, and objc-config.h
|
||||
/// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/
|
||||
/// http://llvm.org/svn/llvm-project/lldb/trunk/examples/summaries/cocoa/objc_runtime.py
|
||||
/// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/
|
||||
BOOL FLEXPointerIsValidObjcObject(const void * ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,309 @@
|
||||
//
|
||||
// FLEXObjcInternal.mm
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner Bennett on 11/1/18.
|
||||
//
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005-2007 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "FLEXObjcInternal.h"
|
||||
#import <objc/runtime.h>
|
||||
#import <malloc/malloc.h>
|
||||
|
||||
#define ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#define NEVER_INLINE inline __attribute__((noinline))
|
||||
|
||||
// The macros below are copied straight from
|
||||
// objc-internal.h, objc-private.h, objc-object.h, and objc-config.h with
|
||||
// as few modifications as possible. Changes are noted in boxed comments.
|
||||
// https://opensource.apple.com/source/objc4/objc4-723/
|
||||
// https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-internal.h.auto.html
|
||||
// https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-private.h.auto.html
|
||||
// https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-config.h.auto.html
|
||||
// https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-object.h.auto.html
|
||||
|
||||
/////////////////////
|
||||
// objc-internal.h //
|
||||
/////////////////////
|
||||
|
||||
#if TARGET_OS_OSX && __x86_64__
|
||||
// 64-bit Mac - tag bit is LSB
|
||||
# define OBJC_MSB_TAGGED_POINTERS 0
|
||||
#else
|
||||
// Everything else - tag bit is MSB
|
||||
# define OBJC_MSB_TAGGED_POINTERS 1
|
||||
#endif
|
||||
|
||||
#define _OBJC_TAG_INDEX_MASK 0x7
|
||||
// array slot includes the tag bit itself
|
||||
#define _OBJC_TAG_SLOT_COUNT 16
|
||||
#define _OBJC_TAG_SLOT_MASK 0xf
|
||||
|
||||
#define _OBJC_TAG_EXT_INDEX_MASK 0xff
|
||||
// array slot has no extra bits
|
||||
#define _OBJC_TAG_EXT_SLOT_COUNT 256
|
||||
#define _OBJC_TAG_EXT_SLOT_MASK 0xff
|
||||
|
||||
#if OBJC_MSB_TAGGED_POINTERS
|
||||
# define _OBJC_TAG_MASK (1UL<<63)
|
||||
# define _OBJC_TAG_INDEX_SHIFT 60
|
||||
# define _OBJC_TAG_SLOT_SHIFT 60
|
||||
# define _OBJC_TAG_PAYLOAD_LSHIFT 4
|
||||
# define _OBJC_TAG_PAYLOAD_RSHIFT 4
|
||||
# define _OBJC_TAG_EXT_MASK (0xfUL<<60)
|
||||
# define _OBJC_TAG_EXT_INDEX_SHIFT 52
|
||||
# define _OBJC_TAG_EXT_SLOT_SHIFT 52
|
||||
# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 12
|
||||
# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
|
||||
#else
|
||||
# define _OBJC_TAG_MASK 1UL
|
||||
# define _OBJC_TAG_INDEX_SHIFT 1
|
||||
# define _OBJC_TAG_SLOT_SHIFT 0
|
||||
# define _OBJC_TAG_PAYLOAD_LSHIFT 0
|
||||
# define _OBJC_TAG_PAYLOAD_RSHIFT 4
|
||||
# define _OBJC_TAG_EXT_MASK 0xfUL
|
||||
# define _OBJC_TAG_EXT_INDEX_SHIFT 4
|
||||
# define _OBJC_TAG_EXT_SLOT_SHIFT 4
|
||||
# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 0
|
||||
# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////
|
||||
// originally _objc_isTaggedPointer //
|
||||
//////////////////////////////////////
|
||||
static BOOL flex_isTaggedPointer(const void *ptr)
|
||||
{
|
||||
return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// objc-config.h //
|
||||
///////////////////
|
||||
|
||||
// Define SUPPORT_INDEXED_ISA=1 on platforms that store the class in the isa
|
||||
// field as an index into a class table.
|
||||
#if __ARM_ARCH_7K__ >= 2
|
||||
# define SUPPORT_INDEXED_ISA 1
|
||||
#else
|
||||
# define SUPPORT_INDEXED_ISA 0
|
||||
#endif
|
||||
|
||||
// Define SUPPORT_PACKED_ISA=1 on platforms that store the class in the isa
|
||||
// field as a maskable pointer with other data around it.
|
||||
#if (!__LP64__ || TARGET_OS_WIN32 || TARGET_OS_SIMULATOR)
|
||||
# define SUPPORT_PACKED_ISA 0
|
||||
#else
|
||||
# define SUPPORT_PACKED_ISA 1
|
||||
#endif
|
||||
|
||||
// Define SUPPORT_NONPOINTER_ISA=1 on any platform that may store something
|
||||
// in the isa field that is not a raw pointer.
|
||||
#if !SUPPORT_INDEXED_ISA && !SUPPORT_PACKED_ISA
|
||||
# define SUPPORT_NONPOINTER_ISA 0
|
||||
#else
|
||||
# define SUPPORT_NONPOINTER_ISA 1
|
||||
#endif
|
||||
|
||||
////////////////////
|
||||
// objc-private.h //
|
||||
////////////////////
|
||||
|
||||
union isa_t
|
||||
{
|
||||
isa_t() { }
|
||||
isa_t(uintptr_t value) : bits(value) { }
|
||||
|
||||
Class cls;
|
||||
uintptr_t bits;
|
||||
|
||||
#if SUPPORT_PACKED_ISA
|
||||
|
||||
// extra_rc must be the MSB-most field (so it matches carry/overflow flags)
|
||||
// nonpointer must be the LSB (fixme or get rid of it)
|
||||
// shiftcls must occupy the same bits that a real class pointer would
|
||||
// bits + RC_ONE is equivalent to extra_rc + 1
|
||||
// RC_HALF is the high bit of extra_rc (i.e. half of its range)
|
||||
|
||||
// future expansion:
|
||||
// uintptr_t fast_rr : 1; // no r/r overrides
|
||||
// uintptr_t lock : 2; // lock for atomic property, @synch
|
||||
// uintptr_t extraBytes : 1; // allocated with extra bytes
|
||||
|
||||
# if __arm64__
|
||||
# define ISA_MASK 0x0000000ffffffff8ULL
|
||||
# define ISA_MAGIC_MASK 0x000003f000000001ULL
|
||||
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
|
||||
struct {
|
||||
uintptr_t nonpointer : 1;
|
||||
uintptr_t has_assoc : 1;
|
||||
uintptr_t has_cxx_dtor : 1;
|
||||
uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
|
||||
uintptr_t magic : 6;
|
||||
uintptr_t weakly_referenced : 1;
|
||||
uintptr_t deallocating : 1;
|
||||
uintptr_t has_sidetable_rc : 1;
|
||||
uintptr_t extra_rc : 19;
|
||||
# define RC_ONE (1ULL<<45)
|
||||
# define RC_HALF (1ULL<<18)
|
||||
};
|
||||
|
||||
# elif __x86_64__
|
||||
# define ISA_MASK 0x00007ffffffffff8ULL
|
||||
# define ISA_MAGIC_MASK 0x001f800000000001ULL
|
||||
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
|
||||
struct {
|
||||
uintptr_t nonpointer : 1;
|
||||
uintptr_t has_assoc : 1;
|
||||
uintptr_t has_cxx_dtor : 1;
|
||||
uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
|
||||
uintptr_t magic : 6;
|
||||
uintptr_t weakly_referenced : 1;
|
||||
uintptr_t deallocating : 1;
|
||||
uintptr_t has_sidetable_rc : 1;
|
||||
uintptr_t extra_rc : 8;
|
||||
# define RC_ONE (1ULL<<56)
|
||||
# define RC_HALF (1ULL<<7)
|
||||
};
|
||||
|
||||
# else
|
||||
# error unknown architecture for packed isa
|
||||
# endif
|
||||
|
||||
// SUPPORT_PACKED_ISA
|
||||
#endif
|
||||
|
||||
|
||||
#if SUPPORT_INDEXED_ISA
|
||||
|
||||
# if __ARM_ARCH_7K__ >= 2
|
||||
|
||||
# define ISA_INDEX_IS_NPI 1
|
||||
# define ISA_INDEX_MASK 0x0001FFFC
|
||||
# define ISA_INDEX_SHIFT 2
|
||||
# define ISA_INDEX_BITS 15
|
||||
# define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)
|
||||
# define ISA_INDEX_MAGIC_MASK 0x001E0001
|
||||
# define ISA_INDEX_MAGIC_VALUE 0x001C0001
|
||||
struct {
|
||||
uintptr_t nonpointer : 1;
|
||||
uintptr_t has_assoc : 1;
|
||||
uintptr_t indexcls : 15;
|
||||
uintptr_t magic : 4;
|
||||
uintptr_t has_cxx_dtor : 1;
|
||||
uintptr_t weakly_referenced : 1;
|
||||
uintptr_t deallocating : 1;
|
||||
uintptr_t has_sidetable_rc : 1;
|
||||
uintptr_t extra_rc : 7;
|
||||
# define RC_ONE (1ULL<<25)
|
||||
# define RC_HALF (1ULL<<6)
|
||||
};
|
||||
|
||||
# else
|
||||
# error unknown architecture for indexed isa
|
||||
# endif
|
||||
|
||||
// SUPPORT_INDEXED_ISA
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
///////////////////
|
||||
// objc-object.h //
|
||||
///////////////////
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// originally objc_object::isExtTaggedPointer //
|
||||
////////////////////////////////////////////////
|
||||
static BOOL flex_isExtTaggedPointer(const void *ptr)
|
||||
{
|
||||
return ((uintptr_t)ptr & _OBJC_TAG_EXT_MASK) == _OBJC_TAG_EXT_MASK;
|
||||
}
|
||||
|
||||
struct flex_objc_object {
|
||||
isa_t isa;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// Returns nil on platforms without nonpointer isa. //
|
||||
// Supporting those platforms would be too complicated //
|
||||
// for such a niche feature anyway. - @NSExceptional //
|
||||
// //
|
||||
// Code modified from objc_object::ISA() on 11/04/18 //
|
||||
//////////////////////////////////////////////////////////
|
||||
static id flex_getIsa(const flex_objc_object *object) {
|
||||
#if SUPPORT_NONPOINTER_ISA
|
||||
if (object->isa.nonpointer) {
|
||||
return object_getClass((__bridge id)object);
|
||||
}
|
||||
return (__bridge Class)(void *)object->isa.bits;
|
||||
#else
|
||||
return nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
// FLEXObjectInternal //
|
||||
// No Apple code beyond this point //
|
||||
/////////////////////////////////////
|
||||
|
||||
extern "C" {
|
||||
/// Assumes memory is valid and readable.
|
||||
/// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/
|
||||
BOOL FLEXPointerIsValidObjcObject(const void * ptr)
|
||||
{
|
||||
uintptr_t pointer = (uintptr_t)ptr;
|
||||
|
||||
if (!ptr) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Tagged pointers have 0x1 set, no other valid pointers do
|
||||
// objc-internal.h -> _objc_isTaggedPointer()
|
||||
if (flex_isTaggedPointer(ptr) || flex_isExtTaggedPointer(ptr)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Check pointer alignment
|
||||
if ((pointer % sizeof(uintptr_t)) != 0) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// From LLDB:
|
||||
// Pointers in a class_t will only have bits 0 through 46 set,
|
||||
// so if any pointer has bits 47 through 63 high, we know that this is not a valid isa
|
||||
// http://llvm.org/svn/llvm-project/lldb/trunk/examples/summaries/cocoa/objc_runtime.py
|
||||
if ((pointer & 0xFFFF800000000000) != 0) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html :
|
||||
if (flex_getIsa((const flex_objc_object *)ptr)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
+ (UIImage *)listIcon;
|
||||
+ (UIImage *)moveIcon;
|
||||
+ (UIImage *)selectIcon;
|
||||
+ (UIImage *)checkerPattern;
|
||||
|
||||
+ (UIImage *)jsonIcon;
|
||||
+ (UIImage *)textPlainIcon;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -25,10 +25,44 @@ extern NSString *const kFLEXUtilityAttributeWeak;
|
||||
extern NSString *const kFLEXUtilityAttributeGarbageCollectable;
|
||||
extern NSString *const kFLEXUtilityAttributeOldStyleTypeEncoding;
|
||||
|
||||
typedef NS_ENUM(char, FLEXTypeEncoding)
|
||||
{
|
||||
FLEXTypeEncodingUnknown = '?',
|
||||
FLEXTypeEncodingChar = 'c',
|
||||
FLEXTypeEncodingInt = 'i',
|
||||
FLEXTypeEncodingShort = 's',
|
||||
FLEXTypeEncodingLong = 'l',
|
||||
FLEXTypeEncodingLongLong = 'q',
|
||||
FLEXTypeEncodingUnsignedChar = 'C',
|
||||
FLEXTypeEncodingUnsignedInt = 'I',
|
||||
FLEXTypeEncodingUnsignedShort = 'S',
|
||||
FLEXTypeEncodingUnsignedLong = 'L',
|
||||
FLEXTypeEncodingUnsignedLongLong = 'Q',
|
||||
FLEXTypeEncodingFloat = 'f',
|
||||
FLEXTypeEncodingDouble = 'd',
|
||||
FLEXTypeEncodingCBool = 'B',
|
||||
FLEXTypeEncodingVoid = 'v',
|
||||
FLEXTypeEncodingCString = '*',
|
||||
FLEXTypeEncodingObjcObject = '@',
|
||||
FLEXTypeEncodingObjcClass = '#',
|
||||
FLEXTypeEncodingSelector = ':',
|
||||
FLEXTypeEncodingArray = '[',
|
||||
FLEXTypeEncodingStruct = '{',
|
||||
FLEXTypeEncodingUnion = '(',
|
||||
FLEXTypeEncodingBitField = 'b',
|
||||
FLEXTypeEncodingPointer = '^',
|
||||
FLEXTypeEncodingConst = 'r'
|
||||
};
|
||||
|
||||
#define FLEXEncodeClass(class) ("@\"" #class "\"")
|
||||
|
||||
@interface FLEXRuntimeUtility : NSObject
|
||||
|
||||
// General Helpers
|
||||
+ (BOOL)pointerIsValidObjcObject:(const void *)pointer;
|
||||
/// Unwraps raw pointers to objects stored in NSValue, and re-boxes C strings into NSStrings.
|
||||
+ (id)potentiallyUnwrapBoxedPointer:(id)returnedObjectOrNil type:(const FLEXTypeEncoding *)returnType;
|
||||
|
||||
// Property Helpers
|
||||
+ (NSString *)prettyNameForProperty:(objc_property_t)property;
|
||||
+ (NSString *)typeEncodingForProperty:(objc_property_t)property;
|
||||
@@ -37,7 +71,7 @@ extern NSString *const kFLEXUtilityAttributeOldStyleTypeEncoding;
|
||||
+ (NSString *)fullDescriptionForProperty:(objc_property_t)property;
|
||||
+ (id)valueForProperty:(objc_property_t)property onObject:(id)object;
|
||||
+ (NSString *)descriptionForIvarOrPropertyValue:(id)value;
|
||||
+ (void)tryAddPropertyWithName:(const char *)name attributes:(NSDictionary *)attributePairs toClass:(__unsafe_unretained Class)theClass;
|
||||
+ (void)tryAddPropertyWithName:(const char *)name attributes:(NSDictionary<NSString *, NSString *> *)attributePairs toClass:(__unsafe_unretained Class)theClass;
|
||||
|
||||
// Ivar Helpers
|
||||
+ (NSString *)prettyNameForIvar:(Ivar)ivar;
|
||||
@@ -47,6 +81,7 @@ extern NSString *const kFLEXUtilityAttributeOldStyleTypeEncoding;
|
||||
// Method Helpers
|
||||
+ (NSString *)prettyNameForMethod:(Method)method isClassMethod:(BOOL)isClassMethod;
|
||||
+ (NSArray *)prettyArgumentComponentsForMethod:(Method)method;
|
||||
+ (FLEXTypeEncoding *)returnTypeForMethod:(Method)method;
|
||||
|
||||
// Method Calling/Field Editing
|
||||
+ (id)performSelector:(SEL)selector onObject:(id)object withArguments:(NSArray *)arguments error:(NSError * __autoreleasing *)error;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#import "FLEXObjcInternal.h"
|
||||
|
||||
// See https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW6
|
||||
NSString *const kFLEXUtilityAttributeTypeEncoding = @"T";
|
||||
@@ -36,6 +37,57 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
@implementation FLEXRuntimeUtility
|
||||
|
||||
|
||||
#pragma mark - General Helpers (Public)
|
||||
|
||||
+ (BOOL)pointerIsValidObjcObject:(const void *)pointer
|
||||
{
|
||||
return FLEXPointerIsValidObjcObject(pointer);
|
||||
}
|
||||
|
||||
+ (id)potentiallyUnwrapBoxedPointer:(id)returnedObjectOrNil type:(const FLEXTypeEncoding *)returnType
|
||||
{
|
||||
if (!returnedObjectOrNil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSInteger i = 0;
|
||||
if (returnType[i] == FLEXTypeEncodingConst) {
|
||||
i++;
|
||||
}
|
||||
|
||||
BOOL returnsObjectOrClass = returnType[i] == FLEXTypeEncodingObjcObject ||
|
||||
returnType[i] == FLEXTypeEncodingObjcClass;
|
||||
BOOL returnsVoidPointer = returnType[i] == FLEXTypeEncodingPointer &&
|
||||
returnType[i+1] == FLEXTypeEncodingVoid;
|
||||
BOOL returnsCString = returnType[i] == FLEXTypeEncodingCString;
|
||||
|
||||
// If we got back an NSValue and the return type is not an object,
|
||||
// we check to see if the pointer is of a valid object. If not,
|
||||
// we just display the NSValue.
|
||||
if (!returnsObjectOrClass) {
|
||||
// Can only be NSValue since return type is not an object,
|
||||
// so we bail if this doesn't add up
|
||||
if (![returnedObjectOrNil isKindOfClass:[NSValue class]]) {
|
||||
return returnedObjectOrNil;
|
||||
}
|
||||
|
||||
NSValue *value = (NSValue *)returnedObjectOrNil;
|
||||
|
||||
if (returnsCString) {
|
||||
// Wrap char * in NSString
|
||||
const char *string = (const char *)value.pointerValue;
|
||||
returnedObjectOrNil = [NSString stringWithCString:string encoding:NSUTF8StringEncoding];
|
||||
} else if (returnsVoidPointer) {
|
||||
// Cast valid objects disguised as void * to id
|
||||
if ([FLEXRuntimeUtility pointerIsValidObjcObject:value.pointerValue]) {
|
||||
returnedObjectOrNil = (__bridge id)value.pointerValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnedObjectOrNil;
|
||||
}
|
||||
|
||||
#pragma mark - Property Helpers (Public)
|
||||
|
||||
+ (NSString *)prettyNameForProperty:(objc_property_t)property
|
||||
@@ -48,7 +100,7 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
|
||||
+ (NSString *)typeEncodingForProperty:(objc_property_t)property
|
||||
{
|
||||
NSDictionary *attributesDictionary = [self attributesDictionaryForProperty:property];
|
||||
NSDictionary<NSString *, NSString *> *attributesDictionary = [self attributesDictionaryForProperty:property];
|
||||
return attributesDictionary[kFLEXUtilityAttributeTypeEncoding];
|
||||
}
|
||||
|
||||
@@ -73,8 +125,8 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
|
||||
+ (NSString *)fullDescriptionForProperty:(objc_property_t)property
|
||||
{
|
||||
NSDictionary *attributesDictionary = [self attributesDictionaryForProperty:property];
|
||||
NSMutableArray *attributesStrings = [NSMutableArray array];
|
||||
NSDictionary<NSString *, NSString *> *attributesDictionary = [self attributesDictionaryForProperty:property];
|
||||
NSMutableArray<NSString *> *attributesStrings = [NSMutableArray array];
|
||||
|
||||
// Atomicity
|
||||
if (attributesDictionary[kFLEXUtilityAttributeNonAtomic]) {
|
||||
@@ -155,10 +207,14 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!description) {
|
||||
// Single line display - replace newlines and tabs with spaces.
|
||||
description = [[value description] stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
|
||||
description = [description stringByReplacingOccurrencesOfString:@"\t" withString:@" "];
|
||||
@try {
|
||||
if (!description) {
|
||||
// Single line display - replace newlines and tabs with spaces.
|
||||
description = [[value description] stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
|
||||
description = [description stringByReplacingOccurrencesOfString:@"\t" withString:@" "];
|
||||
}
|
||||
} @catch (NSException *e) {
|
||||
description = [@"Thrown: " stringByAppendingString:e.reason ?: @"(nil exception reason)"];
|
||||
}
|
||||
|
||||
if (!description) {
|
||||
@@ -168,7 +224,7 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
return description;
|
||||
}
|
||||
|
||||
+ (void)tryAddPropertyWithName:(const char *)name attributes:(NSDictionary *)attributePairs toClass:(__unsafe_unretained Class)theClass
|
||||
+ (void)tryAddPropertyWithName:(const char *)name attributes:(NSDictionary<NSString *, NSString *> *)attributePairs toClass:(__unsafe_unretained Class)theClass
|
||||
{
|
||||
objc_property_t property = class_getProperty(theClass, name);
|
||||
if (!property) {
|
||||
@@ -209,7 +265,7 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
#ifdef __arm64__
|
||||
// See http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html
|
||||
const char *name = ivar_getName(ivar);
|
||||
if (type[0] == @encode(Class)[0] && strcmp(name, "isa") != 0) {
|
||||
if (type[0] == @encode(Class)[0] && strcmp(name, "isa") == 0) {
|
||||
value = object_getClass(object);
|
||||
} else
|
||||
#endif
|
||||
@@ -262,7 +318,7 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
NSString *readableReturnType = [self readableTypeForEncoding:@(returnType)];
|
||||
free(returnType);
|
||||
NSString *prettyName = [NSString stringWithFormat:@"%@ (%@)", methodTypeString, readableReturnType];
|
||||
NSArray *components = [self prettyArgumentComponentsForMethod:method];
|
||||
NSArray<NSString *> *components = [self prettyArgumentComponentsForMethod:method];
|
||||
if ([components count] > 0) {
|
||||
prettyName = [prettyName stringByAppendingString:[components componentsJoinedByString:@" "]];
|
||||
} else {
|
||||
@@ -272,25 +328,38 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
return prettyName;
|
||||
}
|
||||
|
||||
+ (NSArray *)prettyArgumentComponentsForMethod:(Method)method
|
||||
+ (NSArray<NSString *> *)prettyArgumentComponentsForMethod:(Method)method
|
||||
{
|
||||
NSMutableArray *components = [NSMutableArray array];
|
||||
NSMutableArray<NSString *> *components = [NSMutableArray array];
|
||||
|
||||
NSString *selectorName = NSStringFromSelector(method_getName(method));
|
||||
NSArray *selectorComponents = [selectorName componentsSeparatedByString:@":"];
|
||||
unsigned int numberOfArguments = method_getNumberOfArguments(method);
|
||||
NSMutableArray<NSString *> *selectorComponents = [[selectorName componentsSeparatedByString:@":"] mutableCopy];
|
||||
|
||||
for (unsigned int argIndex = kFLEXNumberOfImplicitArgs; argIndex < numberOfArguments; argIndex++) {
|
||||
char *argType = method_copyArgumentType(method, argIndex);
|
||||
NSString *readableArgType = [self readableTypeForEncoding:@(argType)];
|
||||
// this is a workaround cause method_getNumberOfArguments() returns wrong number for some methods
|
||||
if (selectorComponents.count == 1) {
|
||||
return @[];
|
||||
}
|
||||
|
||||
if ([selectorComponents.lastObject isEqualToString:@""]) {
|
||||
[selectorComponents removeLastObject];
|
||||
}
|
||||
|
||||
for (unsigned int argIndex = 0; argIndex < selectorComponents.count; argIndex++) {
|
||||
char *argType = method_copyArgumentType(method, argIndex + kFLEXNumberOfImplicitArgs);
|
||||
NSString *readableArgType = (argType != NULL) ? [self readableTypeForEncoding:@(argType)] : nil;
|
||||
free(argType);
|
||||
NSString *prettyComponent = [NSString stringWithFormat:@"%@:(%@) ", [selectorComponents objectAtIndex:argIndex - kFLEXNumberOfImplicitArgs], readableArgType];
|
||||
NSString *prettyComponent = [NSString stringWithFormat:@"%@:(%@) ", [selectorComponents objectAtIndex:argIndex], readableArgType];
|
||||
[components addObject:prettyComponent];
|
||||
}
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
+ (FLEXTypeEncoding *)returnTypeForMethod:(Method)method
|
||||
{
|
||||
return (FLEXTypeEncoding *)method_copyReturnType(method);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Method Calling/Field Editing (Public)
|
||||
|
||||
@@ -299,7 +368,7 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
// Bail if the object won't respond to this selector.
|
||||
if (![object respondsToSelector:selector]) {
|
||||
if (error) {
|
||||
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@"%@ does not respond to the selector %@", object, NSStringFromSelector(selector)]};
|
||||
NSDictionary<NSString *, id> *userInfo = @{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@"%@ does not respond to the selector %@", object, NSStringFromSelector(selector)]};
|
||||
*error = [NSError errorWithDomain:FLEXRuntimeUtilityErrorDomain code:FLEXRuntimeUtilityErrorCodeDoesNotRecognizeSelector userInfo:userInfo];
|
||||
}
|
||||
return nil;
|
||||
@@ -335,59 +404,71 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
// Ensure that the type encoding on the NSValue matches the type encoding of the argument in the method signature
|
||||
if (strcmp([argumentValue objCType], typeEncodingCString) != 0) {
|
||||
if (error) {
|
||||
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Type encoding mismatch for agrument at index %lu. Value type: %s; Method argument type: %s.", (unsigned long)argumentsArrayIndex, [argumentValue objCType], typeEncodingCString]};
|
||||
NSDictionary<NSString *, id> *userInfo = @{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Type encoding mismatch for agrument at index %lu. Value type: %s; Method argument type: %s.", (unsigned long)argumentsArrayIndex, [argumentValue objCType], typeEncodingCString]};
|
||||
*error = [NSError errorWithDomain:FLEXRuntimeUtilityErrorDomain code:FLEXRuntimeUtilityErrorCodeArgumentTypeMismatch userInfo:userInfo];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSUInteger bufferSize = 0;
|
||||
@try {
|
||||
NSUInteger bufferSize = 0;
|
||||
|
||||
// NSGetSizeAndAlignment barfs on type encoding for bitfields.
|
||||
NSGetSizeAndAlignment(typeEncodingCString, &bufferSize, NULL);
|
||||
|
||||
if (bufferSize > 0) {
|
||||
void *buffer = calloc(bufferSize, 1);
|
||||
[argumentValue getValue:buffer];
|
||||
[invocation setArgument:buffer atIndex:argumentIndex];
|
||||
free(buffer);
|
||||
}
|
||||
} @catch (NSException *exception) { }
|
||||
|
||||
if (bufferSize > 0) {
|
||||
void *buffer = calloc(bufferSize, 1);
|
||||
[argumentValue getValue:buffer];
|
||||
[invocation setArgument:buffer atIndex:argumentIndex];
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to invoke the invocation but guard against an exception being thrown.
|
||||
BOOL successfullyInvoked = NO;
|
||||
id returnObject = nil;
|
||||
@try {
|
||||
// Some methods are not fit to be called...
|
||||
// Looking at you -[UIResponder(UITextInputAdditions) _caretRect]
|
||||
[invocation invoke];
|
||||
successfullyInvoked = YES;
|
||||
} @catch (NSException *exception) {
|
||||
// Bummer...
|
||||
if (error) {
|
||||
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Exception thrown while performing selector %@ on object %@", NSStringFromSelector(selector), object]};
|
||||
*error = [NSError errorWithDomain:FLEXRuntimeUtilityErrorDomain code:FLEXRuntimeUtilityErrorCodeInvocationFailed userInfo:userInfo];
|
||||
}
|
||||
}
|
||||
|
||||
// Retreive the return value and box if necessary.
|
||||
id returnObject = nil;
|
||||
if (successfullyInvoked) {
|
||||
|
||||
// Retreive the return value and box if necessary.
|
||||
const char *returnType = [methodSignature methodReturnType];
|
||||
|
||||
if (returnType[0] == @encode(id)[0] || returnType[0] == @encode(Class)[0]) {
|
||||
// Return value is an object.
|
||||
__unsafe_unretained id objectReturnedFromMethod = nil;
|
||||
[invocation getReturnValue:&objectReturnedFromMethod];
|
||||
returnObject = objectReturnedFromMethod;
|
||||
} else if (returnType[0] != @encode(void)[0]) {
|
||||
// Will use arbitrary buffer for return value and box it.
|
||||
void *returnValue = malloc([methodSignature methodReturnLength]);
|
||||
|
||||
if (returnValue) {
|
||||
[invocation getReturnValue:returnValue];
|
||||
returnObject = [self valueForPrimitivePointer:returnValue objCType:returnType];
|
||||
free(returnValue);
|
||||
}
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
// Bummer...
|
||||
if (error) {
|
||||
// "… on <class>" / "… on instance of <class>"
|
||||
NSString *class = NSStringFromClass([object class]);
|
||||
NSString *calledOn = object == [object class] ? class : [@"an instance of " stringByAppendingString:class];
|
||||
|
||||
NSString *message = [NSString stringWithFormat:@"Exception '%@' thrown while performing selector '%@' on %@.\nReason:\n\n%@",
|
||||
exception.name,
|
||||
NSStringFromSelector(selector),
|
||||
calledOn,
|
||||
exception.reason];
|
||||
|
||||
*error = [NSError errorWithDomain:FLEXRuntimeUtilityErrorDomain
|
||||
code:FLEXRuntimeUtilityErrorCodeInvocationFailed
|
||||
userInfo:@{ NSLocalizedDescriptionKey : message }];
|
||||
}
|
||||
}
|
||||
|
||||
return returnObject;
|
||||
@@ -436,9 +517,9 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
NSString *editableDescription = nil;
|
||||
|
||||
if (object) {
|
||||
// This is a hack to use JSON serialzation for our editable objects.
|
||||
// This is a hack to use JSON serialization for our editable objects.
|
||||
// NSJSONSerialization doesn't allow writing fragments - the top level object must be an array or dictionary.
|
||||
// We always wrap the object inside an array and then strip the outter square braces off the final string.
|
||||
// We always wrap the object inside an array and then strip the outer square braces off the final string.
|
||||
NSArray *wrappedObject = @[object];
|
||||
if ([NSJSONSerialization isValidJSONObject:wrappedObject]) {
|
||||
NSString *wrappedDescription = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:wrappedObject options:0 error:NULL] encoding:NSUTF8StringEncoding];
|
||||
@@ -550,12 +631,12 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
|
||||
#pragma mark - Internal Helpers
|
||||
|
||||
+ (NSDictionary *)attributesDictionaryForProperty:(objc_property_t)property
|
||||
+ (NSDictionary<NSString *, NSString *> *)attributesDictionaryForProperty:(objc_property_t)property
|
||||
{
|
||||
NSString *attributes = @(property_getAttributes(property));
|
||||
// Thanks to MAObjcRuntime for inspiration here.
|
||||
NSArray *attributePairs = [attributes componentsSeparatedByString:@","];
|
||||
NSMutableDictionary *attributesDictionary = [NSMutableDictionary dictionaryWithCapacity:[attributePairs count]];
|
||||
NSArray<NSString *> *attributePairs = [attributes componentsSeparatedByString:@","];
|
||||
NSMutableDictionary<NSString *, NSString *> *attributesDictionary = [NSMutableDictionary dictionaryWithCapacity:[attributePairs count]];
|
||||
for (NSString *attributePair in attributePairs) {
|
||||
[attributesDictionary setObject:[attributePair substringFromIndex:1] forKey:[attributePair substringToIndex:1]];
|
||||
}
|
||||
@@ -674,7 +755,7 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
|
||||
+ (NSValue *)valueForPrimitivePointer:(void *)pointer objCType:(const char *)type
|
||||
{
|
||||
// CASE marcro inspired by https://www.mikeash.com/pyblog/friday-qa-2013-02-08-lets-build-key-value-coding.html
|
||||
// CASE macro inspired by https://www.mikeash.com/pyblog/friday-qa-2013-02-08-lets-build-key-value-coding.html
|
||||
#define CASE(ctype, selectorpart) \
|
||||
if(strcmp(type, @encode(ctype)) == 0) { \
|
||||
return [NSNumber numberWith ## selectorpart: *(ctype *)pointer]; \
|
||||
|
||||
@@ -6,18 +6,27 @@
|
||||
// Copyright (c) 2014 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Availability.h>
|
||||
#import <AvailabilityInternal.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#define FLEXFloor(x) (floor([[UIScreen mainScreen] scale] * (x)) / [[UIScreen mainScreen] scale])
|
||||
|
||||
#if defined(__IPHONE_11_0)
|
||||
#define FLEX_AT_LEAST_IOS11_SDK (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
|
||||
#else
|
||||
#define FLEX_AT_LEAST_IOS11_SDK NO
|
||||
#endif
|
||||
|
||||
@interface FLEXUtility : NSObject
|
||||
|
||||
+ (UIColor *)consistentRandomColorForObject:(id)object;
|
||||
+ (NSString *)descriptionForView:(UIView *)view includingFrame:(BOOL)includeFrame;
|
||||
+ (NSString *)stringForCGRect:(CGRect)rect;
|
||||
+ (UIViewController *)viewControllerForView:(UIView *)view;
|
||||
+ (UIViewController *)viewControllerForAncestralView:(UIView *)view;
|
||||
+ (NSString *)detailDescriptionForView:(UIView *)view;
|
||||
+ (UIImage *)circularImageWithColor:(UIColor *)color radius:(CGFloat)radius;
|
||||
+ (UIColor *)scrollViewGrayColor;
|
||||
@@ -34,11 +43,14 @@
|
||||
+ (UIImage *)thumbnailedImageWithMaxPixelDimension:(NSInteger)dimension fromImageData:(NSData *)data;
|
||||
+ (NSString *)stringFromRequestDuration:(NSTimeInterval)duration;
|
||||
+ (NSString *)statusCodeStringFromURLResponse:(NSURLResponse *)response;
|
||||
+ (NSDictionary *)dictionaryFromQuery:(NSString *)query;
|
||||
+ (BOOL)isErrorStatusCodeFromURLResponse:(NSURLResponse *)response;
|
||||
+ (NSDictionary<NSString *, id> *)dictionaryFromQuery:(NSString *)query;
|
||||
+ (NSString *)prettyJSONStringFromData:(NSData *)data;
|
||||
+ (BOOL)isValidJSONData:(NSData *)data;
|
||||
+ (NSData *)inflatedDataFromCompressedData:(NSData *)compressedData;
|
||||
|
||||
+ (NSArray<UIWindow *> *)allWindows;
|
||||
|
||||
// Swizzling utilities
|
||||
|
||||
+ (SEL)swizzledSelectorForSelector:(SEL)selector;
|
||||
|
||||
@@ -58,6 +58,18 @@
|
||||
return viewController;
|
||||
}
|
||||
|
||||
+ (UIViewController *)viewControllerForAncestralView:(UIView *)view{
|
||||
UIViewController *viewController = nil;
|
||||
SEL viewDelSel = NSSelectorFromString([NSString stringWithFormat:@"%@ewControllerForAncestor", @"_vi"]);
|
||||
if ([view respondsToSelector:viewDelSel]) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
viewController = [view performSelector:viewDelSel];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
return viewController;
|
||||
}
|
||||
|
||||
+ (NSString *)detailDescriptionForView:(UIView *)view
|
||||
{
|
||||
return [NSString stringWithFormat:@"frame %@", [self stringForCGRect:view.frame]];
|
||||
@@ -93,12 +105,12 @@
|
||||
|
||||
+ (NSString *)applicationImageName
|
||||
{
|
||||
return [[NSBundle mainBundle] executablePath];
|
||||
return [NSBundle mainBundle].executablePath;
|
||||
}
|
||||
|
||||
+ (NSString *)applicationName
|
||||
{
|
||||
return [[[FLEXUtility applicationImageName] componentsSeparatedByString:@"/"] lastObject];
|
||||
return [FLEXUtility applicationImageName].lastPathComponent;
|
||||
}
|
||||
|
||||
+ (NSString *)safeDescriptionForObject:(id)object
|
||||
@@ -126,7 +138,7 @@
|
||||
|
||||
+ (NSString *)stringByEscapingHTMLEntitiesInString:(NSString *)originalString
|
||||
{
|
||||
static NSDictionary *escapingDictionary = nil;
|
||||
static NSDictionary<NSString *, NSString *> *escapingDictionary = nil;
|
||||
static NSRegularExpression *regex = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
@@ -144,7 +156,7 @@
|
||||
|
||||
NSMutableString *mutableString = [originalString mutableCopy];
|
||||
|
||||
NSArray *matches = [regex matchesInString:mutableString options:0 range:NSMakeRange(0, [mutableString length])];
|
||||
NSArray<NSTextCheckingResult *> *matches = [regex matchesInString:mutableString options:0 range:NSMakeRange(0, [mutableString length])];
|
||||
for (NSTextCheckingResult *result in [matches reverseObjectEnumerator]) {
|
||||
NSString *foundString = [mutableString substringWithRange:result.range];
|
||||
NSString *replacementString = escapingDictionary[foundString];
|
||||
@@ -158,7 +170,7 @@
|
||||
|
||||
+ (UIInterfaceOrientationMask)infoPlistSupportedInterfaceOrientationsMask
|
||||
{
|
||||
NSArray *supportedOrientations = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"];
|
||||
NSArray<NSString *> *supportedOrientations = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"];
|
||||
UIInterfaceOrientationMask supportedOrientationsMask = 0;
|
||||
if ([supportedOrientations containsObject:@"UIInterfaceOrientationPortrait"]) {
|
||||
supportedOrientationsMask |= UIInterfaceOrientationMaskPortrait;
|
||||
@@ -191,9 +203,9 @@
|
||||
UIImage *thumbnail = nil;
|
||||
CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, 0);
|
||||
if (imageSource) {
|
||||
NSDictionary *options = @{ (__bridge id)kCGImageSourceCreateThumbnailWithTransform : @YES,
|
||||
(__bridge id)kCGImageSourceCreateThumbnailFromImageAlways : @YES,
|
||||
(__bridge id)kCGImageSourceThumbnailMaxPixelSize : @(dimension) };
|
||||
NSDictionary<NSString *, id> *options = @{ (__bridge id)kCGImageSourceCreateThumbnailWithTransform : @YES,
|
||||
(__bridge id)kCGImageSourceCreateThumbnailFromImageAlways : @YES,
|
||||
(__bridge id)kCGImageSourceThumbnailMaxPixelSize : @(dimension) };
|
||||
|
||||
CGImageRef scaledImageRef = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, (__bridge CFDictionaryRef)options);
|
||||
if (scaledImageRef) {
|
||||
@@ -237,15 +249,27 @@
|
||||
return httpResponseString;
|
||||
}
|
||||
|
||||
+ (NSDictionary *)dictionaryFromQuery:(NSString *)query
|
||||
+ (BOOL)isErrorStatusCodeFromURLResponse:(NSURLResponse *)response {
|
||||
NSIndexSet *errorStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(400, 200)];
|
||||
|
||||
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
return [errorStatusCodes containsIndex:httpResponse.statusCode];
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
+ (NSDictionary<NSString *, id> *)dictionaryFromQuery:(NSString *)query
|
||||
{
|
||||
NSMutableDictionary *queryDictionary = [NSMutableDictionary dictionary];
|
||||
NSMutableDictionary<NSString *, id> *queryDictionary = [NSMutableDictionary dictionary];
|
||||
|
||||
// [a=1, b=2, c=3]
|
||||
NSArray *queryComponents = [query componentsSeparatedByString:@"&"];
|
||||
NSArray<NSString *> *queryComponents = [query componentsSeparatedByString:@"&"];
|
||||
for (NSString *keyValueString in queryComponents) {
|
||||
// [a, 1]
|
||||
NSArray *components = [keyValueString componentsSeparatedByString:@"="];
|
||||
NSArray<NSString *> *components = [keyValueString componentsSeparatedByString:@"="];
|
||||
if ([components count] == 2) {
|
||||
NSString *key = [[components firstObject] stringByRemovingPercentEncoding];
|
||||
id value = [[components lastObject] stringByRemovingPercentEncoding];
|
||||
@@ -326,6 +350,28 @@
|
||||
return inflatedData;
|
||||
}
|
||||
|
||||
+ (NSArray<UIWindow *> *)allWindows
|
||||
{
|
||||
BOOL includeInternalWindows = YES;
|
||||
BOOL onlyVisibleWindows = NO;
|
||||
|
||||
NSArray<NSString *> *allWindowsComponents = @[@"al", @"lWindo", @"wsIncl", @"udingInt", @"ernalWin", @"dows:o", @"nlyVisi", @"bleWin", @"dows:"];
|
||||
SEL allWindowsSelector = NSSelectorFromString([allWindowsComponents componentsJoinedByString:@""]);
|
||||
|
||||
NSMethodSignature *methodSignature = [[UIWindow class] methodSignatureForSelector:allWindowsSelector];
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
|
||||
|
||||
invocation.target = [UIWindow class];
|
||||
invocation.selector = allWindowsSelector;
|
||||
[invocation setArgument:&includeInternalWindows atIndex:2];
|
||||
[invocation setArgument:&onlyVisibleWindows atIndex:3];
|
||||
[invocation invoke];
|
||||
|
||||
__unsafe_unretained NSArray<UIWindow *> *windows = nil;
|
||||
[invocation getReturnValue:&windows];
|
||||
return windows;
|
||||
}
|
||||
|
||||
+ (SEL)swizzledSelectorForSelector:(SEL)selector
|
||||
{
|
||||
return NSSelectorFromString([NSString stringWithFormat:@"_flex_swizzle_%x_%@", arc4random(), NSStringFromSelector(selector)]);
|
||||
|
||||
@@ -14,5 +14,6 @@
|
||||
|
||||
@property (nonatomic, assign) NSInteger viewDepth;
|
||||
@property (nonatomic, strong) UIColor *viewColor;
|
||||
@property (nonatomic, strong) UIView *viewBackgroundColorView;
|
||||
|
||||
@end
|
||||
|
||||
@@ -38,25 +38,37 @@
|
||||
self.textLabel.font = [UIFont fontWithName:@"HelveticaNeue-Medium" size:14.0];
|
||||
self.detailTextLabel.font = [FLEXUtility defaultTableViewCellLabelFont];
|
||||
self.accessoryType = UITableViewCellAccessoryDetailButton;
|
||||
|
||||
self.viewBackgroundColorView = [[UIView alloc] init];
|
||||
self.viewBackgroundColorView.clipsToBounds = YES;
|
||||
self.viewBackgroundColorView.layer.borderColor = [UIColor blackColor].CGColor;
|
||||
self.viewBackgroundColorView.layer.borderWidth = 1.0f;
|
||||
[self.contentView addSubview:self.viewBackgroundColorView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
|
||||
{
|
||||
UIColor *originalColour = self.viewBackgroundColorView.backgroundColor;
|
||||
[super setHighlighted:highlighted animated:animated];
|
||||
|
||||
// UITableViewCell changes all subviews in the contentView to backgroundColor = clearColor.
|
||||
// We want to preserve the hierarchy background color when highlighted.
|
||||
self.depthIndicatorView.backgroundColor = [FLEXUtility hierarchyIndentPatternColor];
|
||||
|
||||
self.viewBackgroundColorView.backgroundColor = originalColour;
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
|
||||
{
|
||||
UIColor *originalColour = self.viewBackgroundColorView.backgroundColor;
|
||||
[super setSelected:selected animated:animated];
|
||||
|
||||
// See setHighlighted above.
|
||||
self.depthIndicatorView.backgroundColor = [FLEXUtility hierarchyIndentPatternColor];
|
||||
|
||||
self.viewBackgroundColorView.backgroundColor = originalColour;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
@@ -65,6 +77,7 @@
|
||||
|
||||
const CGFloat kContentPadding = 10.0;
|
||||
const CGFloat kDepthIndicatorWidthMultiplier = 4.0;
|
||||
const CGFloat kViewBackgroundColourDimension = 20;
|
||||
|
||||
CGRect depthIndicatorFrame = CGRectMake(kContentPadding, 0, self.viewDepth * kDepthIndicatorWidthMultiplier, self.contentView.bounds.size.height);
|
||||
self.depthIndicatorView.frame = depthIndicatorFrame;
|
||||
@@ -77,7 +90,7 @@
|
||||
CGRect textLabelFrame = self.textLabel.frame;
|
||||
CGFloat textOriginX = CGRectGetMaxX(circleFrame) + 4.0;
|
||||
textLabelFrame.origin.x = textOriginX;
|
||||
textLabelFrame.size.width = CGRectGetMaxX(self.contentView.bounds) - kContentPadding - textOriginX;
|
||||
textLabelFrame.size.width = CGRectGetMaxX(self.contentView.frame) - kContentPadding - textOriginX - kViewBackgroundColourDimension;
|
||||
self.textLabel.frame = textLabelFrame;
|
||||
|
||||
CGRect detailTextLabelFrame = self.detailTextLabel.frame;
|
||||
@@ -85,6 +98,15 @@
|
||||
detailTextLabelFrame.origin.x = detailOriginX;
|
||||
detailTextLabelFrame.size.width = CGRectGetMaxX(self.contentView.bounds) - kContentPadding - detailOriginX;
|
||||
self.detailTextLabel.frame = detailTextLabelFrame;
|
||||
|
||||
CGRect viewBackgroundColourViewFrame = self.textLabel.frame;
|
||||
viewBackgroundColourViewFrame.size.width = kViewBackgroundColourDimension;
|
||||
viewBackgroundColourViewFrame.size.height = kViewBackgroundColourDimension;
|
||||
viewBackgroundColourViewFrame.origin.x = CGRectGetMaxX(self.textLabel.frame) + kContentPadding;
|
||||
viewBackgroundColourViewFrame.origin.y = ABS(CGRectGetHeight(self.contentView.frame) - CGRectGetHeight(viewBackgroundColourViewFrame)) / 2;
|
||||
|
||||
self.viewBackgroundColorView.frame = viewBackgroundColourViewFrame;
|
||||
self.viewBackgroundColorView.layer.cornerRadius = kViewBackgroundColourDimension / 2;
|
||||
}
|
||||
|
||||
- (void)setViewColor:(UIColor *)viewColor
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
@interface FLEXHierarchyTableViewController : UITableViewController
|
||||
|
||||
- (id)initWithViews:(NSArray *)allViews viewsAtTap:(NSArray *)viewsAtTap selectedView:(UIView *)selectedView depths:(NSDictionary *)depthsForViews;
|
||||
- (instancetype)initWithViews:(NSArray<UIView *> *)allViews viewsAtTap:(NSArray<UIView *> *)viewsAtTap selectedView:(UIView *)selectedView depths:(NSDictionary<NSValue *, NSNumber *> *)depthsForViews;
|
||||
|
||||
@property (nonatomic, weak) id <FLEXHierarchyTableViewControllerDelegate> delegate;
|
||||
|
||||
|
||||
@@ -11,17 +11,18 @@
|
||||
#import "FLEXHierarchyTableViewCell.h"
|
||||
#import "FLEXObjectExplorerViewController.h"
|
||||
#import "FLEXObjectExplorerFactory.h"
|
||||
#import "FLEXResources.h"
|
||||
|
||||
static const NSInteger kFLEXHierarchyScopeViewsAtTapIndex = 0;
|
||||
static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
|
||||
|
||||
@interface FLEXHierarchyTableViewController () <UISearchBarDelegate>
|
||||
|
||||
@property (nonatomic, strong) NSArray *allViews;
|
||||
@property (nonatomic, strong) NSDictionary *depthsForViews;
|
||||
@property (nonatomic, strong) NSArray *viewsAtTap;
|
||||
@property (nonatomic, strong) NSArray<UIView *> *allViews;
|
||||
@property (nonatomic, strong) NSDictionary<NSValue *, NSNumber *> *depthsForViews;
|
||||
@property (nonatomic, strong) NSArray<UIView *> *viewsAtTap;
|
||||
@property (nonatomic, strong) UIView *selectedView;
|
||||
@property (nonatomic, strong) NSArray *displayedViews;
|
||||
@property (nonatomic, strong) NSArray<UIView *> *displayedViews;
|
||||
|
||||
@property (nonatomic, strong) UISearchBar *searchBar;
|
||||
|
||||
@@ -29,7 +30,7 @@ static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
|
||||
|
||||
@implementation FLEXHierarchyTableViewController
|
||||
|
||||
- (id)initWithViews:(NSArray *)allViews viewsAtTap:(NSArray *)viewsAtTap selectedView:(UIView *)selectedView depths:(NSDictionary *)depthsForViews
|
||||
- (instancetype)initWithViews:(NSArray<UIView *> *)allViews viewsAtTap:(NSArray<UIView *> *)viewsAtTap selectedView:(UIView *)selectedView depths:(NSDictionary<NSValue *, NSNumber *> *)depthsForViews
|
||||
{
|
||||
self = [super initWithStyle:UITableViewStylePlain];
|
||||
if (self) {
|
||||
@@ -92,7 +93,7 @@ static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
|
||||
|
||||
- (void)updateDisplayedViews
|
||||
{
|
||||
NSArray *candidateViews = nil;
|
||||
NSArray<UIView *> *candidateViews = nil;
|
||||
if ([self showScopeBar]) {
|
||||
if (self.searchBar.selectedScopeButtonIndex == kFLEXHierarchyScopeViewsAtTapIndex) {
|
||||
candidateViews = self.viewsAtTap;
|
||||
@@ -104,7 +105,7 @@ static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
|
||||
}
|
||||
|
||||
if ([self.searchBar.text length] > 0) {
|
||||
self.displayedViews = [candidateViews filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *candidateView, NSDictionary *bindings) {
|
||||
self.displayedViews = [candidateViews filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *candidateView, NSDictionary<NSString *, id> *bindings) {
|
||||
NSString *title = [FLEXUtility descriptionForView:candidateView includingFrame:NO];
|
||||
NSString *candidateViewPointerAddress = [NSString stringWithFormat:@"%p", candidateView];
|
||||
BOOL matchedViewPointerAddress = [candidateViewPointerAddress rangeOfString:self.searchBar.text options:NSCaseInsensitiveSearch].location != NSNotFound;
|
||||
@@ -180,6 +181,20 @@ static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
|
||||
cell.detailTextLabel.textColor = [UIColor blackColor];
|
||||
}
|
||||
|
||||
// Use a pattern-based colour to simplify application of the checker pattern.
|
||||
static UIColor *checkerPatternColour = nil;
|
||||
static dispatch_once_t once;
|
||||
dispatch_once(&once, ^{
|
||||
checkerPatternColour = [UIColor colorWithPatternImage:[FLEXResources checkerPattern]];
|
||||
});
|
||||
|
||||
UIColor *viewColour = view.backgroundColor;
|
||||
if (!viewColour || [viewColour isEqual:[UIColor clearColor]]) {
|
||||
cell.viewBackgroundColorView.backgroundColor = checkerPatternColour;
|
||||
} else {
|
||||
cell.viewBackgroundColorView.backgroundColor = viewColour;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
self.scrollView.maximumZoomScale = 2.0;
|
||||
[self.view addSubview:self.scrollView];
|
||||
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Copy" style:UIBarButtonItemStylePlain target:self action:@selector(copyButtonPressed:)];
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(actionButtonPressed:)];
|
||||
}
|
||||
|
||||
- (void)viewDidLayoutSubviews
|
||||
@@ -78,9 +78,31 @@
|
||||
self.scrollView.contentInset = UIEdgeInsetsMake(verticalInset, horizontalInset, verticalInset, horizontalInset);
|
||||
}
|
||||
|
||||
- (void)copyButtonPressed:(id)sender
|
||||
- (void)actionButtonPressed:(id)sender
|
||||
{
|
||||
[[UIPasteboard generalPasteboard] setImage:self.image];
|
||||
static BOOL CanSaveToCameraRoll = NO;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
if ([UIDevice currentDevice].systemVersion.floatValue < 10) {
|
||||
CanSaveToCameraRoll = YES;
|
||||
return;
|
||||
}
|
||||
|
||||
NSBundle *mainBundle = [NSBundle mainBundle];
|
||||
if ([mainBundle.infoDictionary.allKeys containsObject:@"NSPhotoLibraryUsageDescription"]) {
|
||||
CanSaveToCameraRoll = YES;
|
||||
} else {
|
||||
NSLog(@"Add NSPhotoLibraryUsageDescription in app's Info.plist for saving captured image into camera roll.");
|
||||
}
|
||||
});
|
||||
|
||||
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:@[self.image] applicationActivities:@[]];
|
||||
|
||||
if (!CanSaveToCameraRoll) {
|
||||
activityVC.excludedActivityTypes = @[UIActivityTypeSaveToCameraRoll];
|
||||
}
|
||||
|
||||
[self presentViewController:activityVC animated:YES completion:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
22679D581C74188D002248FC /* Dog.m in Sources */ = {isa = PBXBuildFile; fileRef = 22679D571C74188D002248FC /* Dog.m */; };
|
||||
22679D5C1C7418B6002248FC /* Owner.m in Sources */ = {isa = PBXBuildFile; fileRef = 22679D5B1C7418B6002248FC /* Owner.m */; };
|
||||
22679D5D1C741A7A002248FC /* dogs.realm in Resources */ = {isa = PBXBuildFile; fileRef = 22679D551C741764002248FC /* dogs.realm */; };
|
||||
3EC6487318FF8A5000024205 /* ReadMe.txt in Resources */ = {isa = PBXBuildFile; fileRef = 3EC6487218FF8A5000024205 /* ReadMe.txt */; };
|
||||
5356823E18F3656900BAAD62 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5356823D18F3656900BAAD62 /* Foundation.framework */; };
|
||||
5356824018F3656900BAAD62 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5356823F18F3656900BAAD62 /* CoreGraphics.framework */; };
|
||||
@@ -47,7 +50,25 @@
|
||||
94CB4D431A97183E0054A905 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 94CB4D421A97183E0054A905 /* libz.dylib */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
22679D691C742141002248FC /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
22679D551C741764002248FC /* dogs.realm */ = {isa = PBXFileReference; lastKnownFileType = file; path = dogs.realm; sourceTree = "<group>"; };
|
||||
22679D561C74188D002248FC /* Dog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Dog.h; sourceTree = "<group>"; };
|
||||
22679D571C74188D002248FC /* Dog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Dog.m; sourceTree = "<group>"; };
|
||||
22679D5A1C7418B6002248FC /* Owner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Owner.h; sourceTree = "<group>"; };
|
||||
22679D5B1C7418B6002248FC /* Owner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Owner.m; sourceTree = "<group>"; };
|
||||
3EC6487218FF8A5000024205 /* ReadMe.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ReadMe.txt; sourceTree = SOURCE_ROOT; };
|
||||
5356823A18F3656900BAAD62 /* UICatalog.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UICatalog.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5356823D18F3656900BAAD62 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
@@ -134,6 +155,18 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
22679D591C741891002248FC /* Realm */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
22679D551C741764002248FC /* dogs.realm */,
|
||||
22679D561C74188D002248FC /* Dog.h */,
|
||||
22679D571C74188D002248FC /* Dog.m */,
|
||||
22679D5A1C7418B6002248FC /* Owner.h */,
|
||||
22679D5B1C7418B6002248FC /* Owner.m */,
|
||||
);
|
||||
name = Realm;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5356823118F3656900BAAD62 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -251,6 +284,7 @@
|
||||
53874F9A18F36B6900510922 /* Application */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
22679D591C741891002248FC /* Realm */,
|
||||
5356824918F3656900BAAD62 /* main.m */,
|
||||
5356827B18F3670300BAAD62 /* AAPLAppDelegate.h */,
|
||||
5356827C18F3670300BAAD62 /* AAPLAppDelegate.m */,
|
||||
@@ -281,6 +315,7 @@
|
||||
5356823618F3656900BAAD62 /* Sources */,
|
||||
5356823718F3656900BAAD62 /* Frameworks */,
|
||||
5356823818F3656900BAAD62 /* Resources */,
|
||||
22679D691C742141002248FC /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -297,7 +332,7 @@
|
||||
5356823218F3656900BAAD62 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0700;
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = f;
|
||||
};
|
||||
buildConfigurationList = 5356823518F3656900BAAD62 /* Build configuration list for PBXProject "UICatalog" */;
|
||||
@@ -323,6 +358,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
22679D5D1C741A7A002248FC /* dogs.realm in Resources */,
|
||||
5356825418F3656900BAAD62 /* Main_iPad.storyboard in Resources */,
|
||||
53874F9918F36B1800510922 /* Localizable.strings in Resources */,
|
||||
5356825918F3656900BAAD62 /* Images.xcassets in Resources */,
|
||||
@@ -338,6 +374,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
22679D5C1C7418B6002248FC /* Owner.m in Sources */,
|
||||
535682AE18F3670300BAAD62 /* AAPLDatePickerController.m in Sources */,
|
||||
535682AB18F3670300BAAD62 /* AAPLButtonViewController.m in Sources */,
|
||||
535682B618F3670300BAAD62 /* AAPLSegmentedControlViewController.m in Sources */,
|
||||
@@ -356,6 +393,7 @@
|
||||
535682B918F3670300BAAD62 /* AAPLStepperViewController.m in Sources */,
|
||||
535682AA18F3670300BAAD62 /* AAPLAppDelegate.m in Sources */,
|
||||
535682B518F3670300BAAD62 /* AAPLProgressViewController.m in Sources */,
|
||||
22679D581C74188D002248FC /* Dog.m in Sources */,
|
||||
535682AD18F3670300BAAD62 /* AAPLCustomToolbarViewController.m in Sources */,
|
||||
535682A818F3670300BAAD62 /* AAPLActivityIndicatorViewController.m in Sources */,
|
||||
535682B818F3670300BAAD62 /* AAPLSplitViewControllerDelegate.m in Sources */,
|
||||
@@ -406,19 +444,32 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
@@ -446,18 +497,31 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
@@ -477,9 +541,14 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
EXCLUDED_SOURCE_FILE_NAMES = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "UICatalog/UICatalog-Prefix.pch";
|
||||
INFOPLIST_FILE = "UICatalog/UICatalog-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.UICatalog";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = app;
|
||||
@@ -492,9 +561,14 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
EXCLUDED_SOURCE_FILE_NAMES = "FLEX*";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "UICatalog/UICatalog-Prefix.pch";
|
||||
INFOPLIST_FILE = "UICatalog/UICatalog-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.UICatalog";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = app;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0700"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -49,6 +49,10 @@
|
||||
|
||||
#if DEBUG
|
||||
#import <FLEX/FLEX.h>
|
||||
#if __has_include(<Realm/Realm.h>)
|
||||
#import "Dog.h"
|
||||
#import "Owner.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@interface AAPLAppDelegate () <NSURLConnectionDataDelegate, NSURLSessionDataDelegate>
|
||||
@@ -66,6 +70,11 @@
|
||||
[[FLEXManager sharedManager] setNetworkDebuggingEnabled:YES];
|
||||
[self sendExampleNetworkRequests];
|
||||
self.repeatingLogExampleTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(sendExampleLogMessage) userInfo:nil repeats:YES];
|
||||
|
||||
#if __has_include(<Realm/Realm.h>)
|
||||
[self setUpRealm];
|
||||
#endif
|
||||
|
||||
#endif
|
||||
return YES;
|
||||
}
|
||||
@@ -173,4 +182,23 @@
|
||||
[self.connections removeObject:connection];
|
||||
}
|
||||
|
||||
#if __has_include(<Realm/Realm.h>)
|
||||
- (void)setUpRealm
|
||||
{
|
||||
NSString *destinationPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
||||
destinationPath = [destinationPath stringByAppendingPathComponent:@"dogs.realm"];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:destinationPath isDirectory:nil]) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"dogs" ofType:@"realm"];
|
||||
if (resourcePath == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSError *error = nil;
|
||||
[[NSFileManager defaultManager] copyItemAtPath:resourcePath toPath:destinationPath error:&error];
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
|
||||
@implementation AAPLSplitViewControllerDelegate
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
|
||||
#pragma mark - UISplitViewControllerDelegate
|
||||
|
||||
// Implementing this delegate method allows us to present the detail view controller with the "More" bar button item.
|
||||
@@ -75,4 +78,6 @@
|
||||
[detailRootViewController.navigationItem setLeftBarButtonItem:nil animated:YES];
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Dog.h
|
||||
// UICatalog
|
||||
//
|
||||
// Created by Tim Oliver on 17/02/2016.
|
||||
// Copyright © 2016 Realm. All rights reserved.
|
||||
//
|
||||
|
||||
#if __has_include(<Realm/Realm.h>)
|
||||
|
||||
#import <Realm/Realm.h>
|
||||
#import "Owner.h"
|
||||
|
||||
@interface Dog : RLMObject
|
||||
@property NSString *name;
|
||||
@property CGFloat height;
|
||||
@property NSDate *birthdate;
|
||||
@property BOOL vaccinated;
|
||||
@property Owner *owner;
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Dog.m
|
||||
// UICatalog
|
||||
//
|
||||
// Created by Tim Oliver on 17/02/2016.
|
||||
// Copyright © 2016 Realm. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Dog.h"
|
||||
|
||||
#if __has_include(<Realm/Realm.h>)
|
||||
|
||||
@implementation Dog
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Owner.h
|
||||
// UICatalog
|
||||
//
|
||||
// Created by Tim Oliver on 17/02/2016.
|
||||
// Copyright © 2016 Realm. All rights reserved.
|
||||
//
|
||||
|
||||
#if __has_include(<Realm/Realm.h>)
|
||||
|
||||
#import <Realm/Realm.h>
|
||||
|
||||
@interface Owner : RLMObject
|
||||
@property NSString *name;
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Owner.m
|
||||
// UICatalog
|
||||
//
|
||||
// Created by Tim Oliver on 17/02/2016.
|
||||
// Copyright © 2016 Realm. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Owner.h"
|
||||
|
||||
#if __has_include(<Realm/Realm.h>)
|
||||
|
||||
@implementation Owner
|
||||
@end
|
||||
|
||||
#endif
|
||||
Binary file not shown.
+3
-3
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "FLEX"
|
||||
spec.version = "2.1.1"
|
||||
spec.version = "2.4.0"
|
||||
spec.summary = "A set of in-app debugging and exploration tools for iOS"
|
||||
spec.description = <<-DESC
|
||||
- Inspect and modify views in the hierarchy.
|
||||
@@ -32,8 +32,8 @@ Pod::Spec.new do |spec|
|
||||
spec.platform = :ios, "8.0"
|
||||
spec.source = { :git => "https://github.com/Flipboard/FLEX.git", :tag => "#{spec.version}" }
|
||||
spec.source_files = "Classes/**/*.{h,m}"
|
||||
spec.frameworks = "CoreGraphics"
|
||||
spec.libraries = "z"
|
||||
spec.frameworks = [ "Foundation", "UIKit", "CoreGraphics" ]
|
||||
spec.libraries = [ "z", "sqlite3" ]
|
||||
spec.requires_arc = true
|
||||
spec.public_header_files = [ "Classes/**/FLEXManager.h", "Classes/FLEX.h" ]
|
||||
end
|
||||
|
||||
+267
-52
@@ -8,6 +8,15 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
04F1CA191C137CF1000A52B0 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 04F1CA181C137CF1000A52B0 /* LICENSE */; };
|
||||
1C27A8B91F0E5A0400F0D02D /* FLEXTestsMethodsList.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C27A8B81F0E5A0400F0D02D /* FLEXTestsMethodsList.m */; };
|
||||
1C27A8BB1F0E5A0400F0D02D /* FLEX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4C941F1B5B20570088C3F2 /* FLEX.framework */; };
|
||||
222C88221C7339DC007CA15F /* FLEXRealmDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 222C88211C7339DC007CA15F /* FLEXRealmDefines.h */; };
|
||||
224D49A81C673AB5000EAB86 /* FLEXRealmDatabaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 224D49A41C673AB5000EAB86 /* FLEXRealmDatabaseManager.h */; };
|
||||
224D49A91C673AB5000EAB86 /* FLEXRealmDatabaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 224D49A51C673AB5000EAB86 /* FLEXRealmDatabaseManager.m */; };
|
||||
224D49AA1C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 224D49A61C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.h */; };
|
||||
224D49AB1C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 224D49A71C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.m */; };
|
||||
2EF6B04D1D494BE50006BDA5 /* FLEXNetworkCurlLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EF6B04B1D494BE50006BDA5 /* FLEXNetworkCurlLogger.m */; };
|
||||
2EF6B04E1D494BE50006BDA5 /* FLEXNetworkCurlLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EF6B04C1D494BE50006BDA5 /* FLEXNetworkCurlLogger.h */; };
|
||||
3A4C94251B5B20570088C3F2 /* FLEX.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94241B5B20570088C3F2 /* FLEX.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
3A4C94C51B5B21410088C3F2 /* FLEXArrayExplorerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C943C1B5B21410088C3F2 /* FLEXArrayExplorerViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C94C61B5B21410088C3F2 /* FLEXArrayExplorerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C943D1B5B21410088C3F2 /* FLEXArrayExplorerViewController.m */; };
|
||||
@@ -87,17 +96,6 @@
|
||||
3A4C95101B5B21410088C3F2 /* FLEXMethodCallingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C948B1B5B21410088C3F2 /* FLEXMethodCallingViewController.m */; };
|
||||
3A4C95111B5B21410088C3F2 /* FLEXPropertyEditorViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C948C1B5B21410088C3F2 /* FLEXPropertyEditorViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C95121B5B21410088C3F2 /* FLEXPropertyEditorViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C948D1B5B21410088C3F2 /* FLEXPropertyEditorViewController.m */; };
|
||||
3A4C95131B5B21410088C3F2 /* FLEXExplorerToolbar.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C948F1B5B21410088C3F2 /* FLEXExplorerToolbar.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C95141B5B21410088C3F2 /* FLEXExplorerToolbar.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94901B5B21410088C3F2 /* FLEXExplorerToolbar.m */; };
|
||||
3A4C95151B5B21410088C3F2 /* FLEXExplorerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94911B5B21410088C3F2 /* FLEXExplorerViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C95161B5B21410088C3F2 /* FLEXExplorerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94921B5B21410088C3F2 /* FLEXExplorerViewController.m */; };
|
||||
3A4C95171B5B21410088C3F2 /* FLEXManager+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94931B5B21410088C3F2 /* FLEXManager+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C95181B5B21410088C3F2 /* FLEXManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94941B5B21410088C3F2 /* FLEXManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
3A4C95191B5B21410088C3F2 /* FLEXManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94951B5B21410088C3F2 /* FLEXManager.m */; };
|
||||
3A4C951A1B5B21410088C3F2 /* FLEXToolbarItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94961B5B21410088C3F2 /* FLEXToolbarItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C951B1B5B21410088C3F2 /* FLEXToolbarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94971B5B21410088C3F2 /* FLEXToolbarItem.m */; };
|
||||
3A4C951C1B5B21410088C3F2 /* FLEXWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94981B5B21410088C3F2 /* FLEXWindow.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C951D1B5B21410088C3F2 /* FLEXWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94991B5B21410088C3F2 /* FLEXWindow.m */; };
|
||||
3A4C951E1B5B21410088C3F2 /* FLEXClassesTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C949B1B5B21410088C3F2 /* FLEXClassesTableViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C951F1B5B21410088C3F2 /* FLEXClassesTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C949C1B5B21410088C3F2 /* FLEXClassesTableViewController.m */; };
|
||||
3A4C95201B5B21410088C3F2 /* FLEXFileBrowserFileOperationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C949D1B5B21410088C3F2 /* FLEXFileBrowserFileOperationController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
@@ -140,7 +138,6 @@
|
||||
679F64861BD53B7B00A8C94C /* FLEXCookiesTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 679F64841BD53B7B00A8C94C /* FLEXCookiesTableViewController.h */; };
|
||||
679F64871BD53B7B00A8C94C /* FLEXCookiesTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 679F64851BD53B7B00A8C94C /* FLEXCookiesTableViewController.m */; };
|
||||
779B1ECE1C0C4D7C001F5E49 /* FLEXDatabaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 779B1EC01C0C4D7C001F5E49 /* FLEXDatabaseManager.h */; };
|
||||
779B1ECF1C0C4D7C001F5E49 /* FLEXDatabaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 779B1EC11C0C4D7C001F5E49 /* FLEXDatabaseManager.m */; };
|
||||
779B1ED01C0C4D7C001F5E49 /* FLEXMultiColumnTableView.h in Headers */ = {isa = PBXBuildFile; fileRef = 779B1EC21C0C4D7C001F5E49 /* FLEXMultiColumnTableView.h */; };
|
||||
779B1ED11C0C4D7C001F5E49 /* FLEXMultiColumnTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 779B1EC31C0C4D7C001F5E49 /* FLEXMultiColumnTableView.m */; };
|
||||
779B1ED21C0C4D7C001F5E49 /* FLEXTableColumnHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 779B1EC41C0C4D7C001F5E49 /* FLEXTableColumnHeader.h */; };
|
||||
@@ -155,13 +152,50 @@
|
||||
779B1EDB1C0C4D7C001F5E49 /* FLEXTableListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 779B1ECD1C0C4D7C001F5E49 /* FLEXTableListViewController.m */; };
|
||||
779B1EDD1C0C4EAD001F5E49 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 779B1EDC1C0C4EAD001F5E49 /* libsqlite3.dylib */; };
|
||||
942DCD871BAE0CA300DB5DC2 /* FLEXKeyboardShortcutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 942DCD831BAE0AD300DB5DC2 /* FLEXKeyboardShortcutManager.m */; };
|
||||
94A515141C4CA1C00063292F /* FLEXManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 94A515131C4CA1C00063292F /* FLEXManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
94A515171C4CA1D70063292F /* FLEXManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 94A515151C4CA1D70063292F /* FLEXManager.m */; };
|
||||
94A515181C4CA1D70063292F /* FLEXManager+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 94A515161C4CA1D70063292F /* FLEXManager+Private.h */; };
|
||||
94A5151D1C4CA1F10063292F /* FLEXExplorerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 94A515191C4CA1F10063292F /* FLEXExplorerViewController.h */; };
|
||||
94A5151E1C4CA1F10063292F /* FLEXExplorerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 94A5151A1C4CA1F10063292F /* FLEXExplorerViewController.m */; };
|
||||
94A5151F1C4CA1F10063292F /* FLEXWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 94A5151B1C4CA1F10063292F /* FLEXWindow.h */; };
|
||||
94A515201C4CA1F10063292F /* FLEXWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 94A5151C1C4CA1F10063292F /* FLEXWindow.m */; };
|
||||
94A515251C4CA2080063292F /* FLEXExplorerToolbar.h in Headers */ = {isa = PBXBuildFile; fileRef = 94A515211C4CA2080063292F /* FLEXExplorerToolbar.h */; };
|
||||
94A515261C4CA2080063292F /* FLEXExplorerToolbar.m in Sources */ = {isa = PBXBuildFile; fileRef = 94A515221C4CA2080063292F /* FLEXExplorerToolbar.m */; };
|
||||
94A515271C4CA2080063292F /* FLEXToolbarItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 94A515231C4CA2080063292F /* FLEXToolbarItem.h */; };
|
||||
94A515281C4CA2080063292F /* FLEXToolbarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 94A515241C4CA2080063292F /* FLEXToolbarItem.m */; };
|
||||
94AAF0381BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 94AAF0361BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
94AAF0391BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 94AAF0371BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.m */; };
|
||||
94AAF03A1BAF2F0300DE8760 /* FLEXKeyboardShortcutManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 942DCD821BAE0AD300DB5DC2 /* FLEXKeyboardShortcutManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
C37A0C93218BAC9600848CA7 /* FLEXObjcInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = C37A0C91218BAC9600848CA7 /* FLEXObjcInternal.h */; };
|
||||
C37A0C94218BAC9600848CA7 /* FLEXObjcInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = C37A0C92218BAC9600848CA7 /* FLEXObjcInternal.mm */; };
|
||||
C395D6D921789BD800BEAD4D /* FLEXColorExplorerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C395D6D721789BD800BEAD4D /* FLEXColorExplorerViewController.h */; };
|
||||
C395D6DA21789BD800BEAD4D /* FLEXColorExplorerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C395D6D821789BD800BEAD4D /* FLEXColorExplorerViewController.m */; };
|
||||
C3DB9F642107FC9600B46809 /* FLEXObjectRef.h in Headers */ = {isa = PBXBuildFile; fileRef = C3DB9F622107FC9600B46809 /* FLEXObjectRef.h */; };
|
||||
C3DB9F652107FC9600B46809 /* FLEXObjectRef.m in Sources */ = {isa = PBXBuildFile; fileRef = C3DB9F632107FC9600B46809 /* FLEXObjectRef.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
1C27A8BC1F0E5A0400F0D02D /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 3A4C94161B5B20570088C3F2 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 3A4C941E1B5B20570088C3F2;
|
||||
remoteInfo = FLEX;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
04F1CA181C137CF1000A52B0 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||
1C27A8B61F0E5A0300F0D02D /* FLEXTestsMethodsList.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FLEXTestsMethodsList.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
1C27A8B81F0E5A0400F0D02D /* FLEXTestsMethodsList.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXTestsMethodsList.m; sourceTree = "<group>"; };
|
||||
1C27A8BA1F0E5A0400F0D02D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
222C88211C7339DC007CA15F /* FLEXRealmDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXRealmDefines.h; sourceTree = "<group>"; };
|
||||
224D49A41C673AB5000EAB86 /* FLEXRealmDatabaseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXRealmDatabaseManager.h; sourceTree = "<group>"; };
|
||||
224D49A51C673AB5000EAB86 /* FLEXRealmDatabaseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXRealmDatabaseManager.m; sourceTree = "<group>"; };
|
||||
224D49A61C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXSQLiteDatabaseManager.h; sourceTree = "<group>"; };
|
||||
224D49A71C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXSQLiteDatabaseManager.m; sourceTree = "<group>"; };
|
||||
2EF6B04B1D494BE50006BDA5 /* FLEXNetworkCurlLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXNetworkCurlLogger.m; sourceTree = "<group>"; };
|
||||
2EF6B04C1D494BE50006BDA5 /* FLEXNetworkCurlLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXNetworkCurlLogger.h; sourceTree = "<group>"; };
|
||||
3A4C941F1B5B20570088C3F2 /* FLEX.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FLEX.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3A4C94231B5B20570088C3F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
3A4C94241B5B20570088C3F2 /* FLEX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEX.h; sourceTree = "<group>"; };
|
||||
@@ -243,17 +277,6 @@
|
||||
3A4C948B1B5B21410088C3F2 /* FLEXMethodCallingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXMethodCallingViewController.m; sourceTree = "<group>"; };
|
||||
3A4C948C1B5B21410088C3F2 /* FLEXPropertyEditorViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXPropertyEditorViewController.h; sourceTree = "<group>"; };
|
||||
3A4C948D1B5B21410088C3F2 /* FLEXPropertyEditorViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXPropertyEditorViewController.m; sourceTree = "<group>"; };
|
||||
3A4C948F1B5B21410088C3F2 /* FLEXExplorerToolbar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXExplorerToolbar.h; sourceTree = "<group>"; };
|
||||
3A4C94901B5B21410088C3F2 /* FLEXExplorerToolbar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXExplorerToolbar.m; sourceTree = "<group>"; };
|
||||
3A4C94911B5B21410088C3F2 /* FLEXExplorerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXExplorerViewController.h; sourceTree = "<group>"; };
|
||||
3A4C94921B5B21410088C3F2 /* FLEXExplorerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXExplorerViewController.m; sourceTree = "<group>"; };
|
||||
3A4C94931B5B21410088C3F2 /* FLEXManager+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FLEXManager+Private.h"; sourceTree = "<group>"; };
|
||||
3A4C94941B5B21410088C3F2 /* FLEXManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXManager.h; sourceTree = "<group>"; };
|
||||
3A4C94951B5B21410088C3F2 /* FLEXManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXManager.m; sourceTree = "<group>"; };
|
||||
3A4C94961B5B21410088C3F2 /* FLEXToolbarItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXToolbarItem.h; sourceTree = "<group>"; };
|
||||
3A4C94971B5B21410088C3F2 /* FLEXToolbarItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXToolbarItem.m; sourceTree = "<group>"; };
|
||||
3A4C94981B5B21410088C3F2 /* FLEXWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXWindow.h; sourceTree = "<group>"; };
|
||||
3A4C94991B5B21410088C3F2 /* FLEXWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXWindow.m; sourceTree = "<group>"; };
|
||||
3A4C949B1B5B21410088C3F2 /* FLEXClassesTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXClassesTableViewController.h; sourceTree = "<group>"; };
|
||||
3A4C949C1B5B21410088C3F2 /* FLEXClassesTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXClassesTableViewController.m; sourceTree = "<group>"; };
|
||||
3A4C949D1B5B21410088C3F2 /* FLEXFileBrowserFileOperationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXFileBrowserFileOperationController.h; sourceTree = "<group>"; };
|
||||
@@ -297,7 +320,6 @@
|
||||
679F64841BD53B7B00A8C94C /* FLEXCookiesTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXCookiesTableViewController.h; sourceTree = "<group>"; };
|
||||
679F64851BD53B7B00A8C94C /* FLEXCookiesTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXCookiesTableViewController.m; sourceTree = "<group>"; };
|
||||
779B1EC01C0C4D7C001F5E49 /* FLEXDatabaseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXDatabaseManager.h; sourceTree = "<group>"; };
|
||||
779B1EC11C0C4D7C001F5E49 /* FLEXDatabaseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXDatabaseManager.m; sourceTree = "<group>"; };
|
||||
779B1EC21C0C4D7C001F5E49 /* FLEXMultiColumnTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXMultiColumnTableView.h; sourceTree = "<group>"; };
|
||||
779B1EC31C0C4D7C001F5E49 /* FLEXMultiColumnTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXMultiColumnTableView.m; sourceTree = "<group>"; };
|
||||
779B1EC41C0C4D7C001F5E49 /* FLEXTableColumnHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXTableColumnHeader.h; sourceTree = "<group>"; };
|
||||
@@ -313,11 +335,36 @@
|
||||
779B1EDC1C0C4EAD001F5E49 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = ../../../../../usr/lib/libsqlite3.dylib; sourceTree = "<group>"; };
|
||||
942DCD821BAE0AD300DB5DC2 /* FLEXKeyboardShortcutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXKeyboardShortcutManager.h; sourceTree = "<group>"; };
|
||||
942DCD831BAE0AD300DB5DC2 /* FLEXKeyboardShortcutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXKeyboardShortcutManager.m; sourceTree = "<group>"; };
|
||||
94A515131C4CA1C00063292F /* FLEXManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXManager.h; sourceTree = "<group>"; };
|
||||
94A515151C4CA1D70063292F /* FLEXManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLEXManager.m; path = Manager/FLEXManager.m; sourceTree = "<group>"; };
|
||||
94A515161C4CA1D70063292F /* FLEXManager+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "FLEXManager+Private.h"; path = "Manager/FLEXManager+Private.h"; sourceTree = "<group>"; };
|
||||
94A515191C4CA1F10063292F /* FLEXExplorerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FLEXExplorerViewController.h; path = ExplorerInterface/FLEXExplorerViewController.h; sourceTree = "<group>"; };
|
||||
94A5151A1C4CA1F10063292F /* FLEXExplorerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLEXExplorerViewController.m; path = ExplorerInterface/FLEXExplorerViewController.m; sourceTree = "<group>"; };
|
||||
94A5151B1C4CA1F10063292F /* FLEXWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FLEXWindow.h; path = ExplorerInterface/FLEXWindow.h; sourceTree = "<group>"; };
|
||||
94A5151C1C4CA1F10063292F /* FLEXWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLEXWindow.m; path = ExplorerInterface/FLEXWindow.m; sourceTree = "<group>"; };
|
||||
94A515211C4CA2080063292F /* FLEXExplorerToolbar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FLEXExplorerToolbar.h; path = Classes/Toolbar/FLEXExplorerToolbar.h; sourceTree = SOURCE_ROOT; };
|
||||
94A515221C4CA2080063292F /* FLEXExplorerToolbar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLEXExplorerToolbar.m; path = Classes/Toolbar/FLEXExplorerToolbar.m; sourceTree = SOURCE_ROOT; };
|
||||
94A515231C4CA2080063292F /* FLEXToolbarItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FLEXToolbarItem.h; path = Classes/Toolbar/FLEXToolbarItem.h; sourceTree = SOURCE_ROOT; };
|
||||
94A515241C4CA2080063292F /* FLEXToolbarItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLEXToolbarItem.m; path = Classes/Toolbar/FLEXToolbarItem.m; sourceTree = SOURCE_ROOT; };
|
||||
94AAF0361BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXKeyboardHelpViewController.h; sourceTree = "<group>"; };
|
||||
94AAF0371BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXKeyboardHelpViewController.m; sourceTree = "<group>"; };
|
||||
C37A0C91218BAC9600848CA7 /* FLEXObjcInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXObjcInternal.h; sourceTree = "<group>"; };
|
||||
C37A0C92218BAC9600848CA7 /* FLEXObjcInternal.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FLEXObjcInternal.mm; sourceTree = "<group>"; };
|
||||
C395D6D721789BD800BEAD4D /* FLEXColorExplorerViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXColorExplorerViewController.h; sourceTree = "<group>"; };
|
||||
C395D6D821789BD800BEAD4D /* FLEXColorExplorerViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXColorExplorerViewController.m; sourceTree = "<group>"; };
|
||||
C3DB9F622107FC9600B46809 /* FLEXObjectRef.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXObjectRef.h; sourceTree = "<group>"; };
|
||||
C3DB9F632107FC9600B46809 /* FLEXObjectRef.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXObjectRef.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
1C27A8B31F0E5A0300F0D02D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1C27A8BB1F0E5A0400F0D02D /* FLEX.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
3A4C941B1B5B20570088C3F2 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -330,10 +377,20 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
1C27A8B71F0E5A0400F0D02D /* FLEXTestsMethodsList */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1C27A8B81F0E5A0400F0D02D /* FLEXTestsMethodsList.m */,
|
||||
1C27A8BA1F0E5A0400F0D02D /* Info.plist */,
|
||||
);
|
||||
path = FLEXTestsMethodsList;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3A4C94151B5B20570088C3F2 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4C94211B5B20570088C3F2 /* FLEX */,
|
||||
1C27A8B71F0E5A0400F0D02D /* FLEXTestsMethodsList */,
|
||||
3A4C95451B5B216C0088C3F2 /* Frameworks */,
|
||||
3A4C94201B5B20570088C3F2 /* Products */,
|
||||
);
|
||||
@@ -343,6 +400,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4C941F1B5B20570088C3F2 /* FLEX.framework */,
|
||||
1C27A8B61F0E5A0300F0D02D /* FLEXTestsMethodsList.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -351,8 +409,11 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4C94241B5B20570088C3F2 /* FLEX.h */,
|
||||
94A515131C4CA1C00063292F /* FLEXManager.h */,
|
||||
94A515111C4C9C1B0063292F /* Manager */,
|
||||
94A515121C4C9E7B0063292F /* ExplorerInterface */,
|
||||
3A4C94661B5B21410088C3F2 /* Editing */,
|
||||
3A4C948E1B5B21410088C3F2 /* ExplorerToolbar */,
|
||||
3A4C948E1B5B21410088C3F2 /* Toolbar */,
|
||||
3A4C949A1B5B21410088C3F2 /* GlobalStateExplorers */,
|
||||
3A4C94B41B5B21410088C3F2 /* Network */,
|
||||
3A4C943B1B5B21410088C3F2 /* ObjectExplorers */,
|
||||
@@ -399,6 +460,8 @@
|
||||
3A4C94511B5B21410088C3F2 /* FLEXViewControllerExplorerViewController.m */,
|
||||
3A4C94521B5B21410088C3F2 /* FLEXViewExplorerViewController.h */,
|
||||
3A4C94531B5B21410088C3F2 /* FLEXViewExplorerViewController.m */,
|
||||
C395D6D721789BD800BEAD4D /* FLEXColorExplorerViewController.h */,
|
||||
C395D6D821789BD800BEAD4D /* FLEXColorExplorerViewController.m */,
|
||||
);
|
||||
path = ObjectExplorers;
|
||||
sourceTree = "<group>";
|
||||
@@ -412,6 +475,8 @@
|
||||
3A4C94581B5B21410088C3F2 /* FLEXMultilineTableViewCell.m */,
|
||||
3A4C94591B5B21410088C3F2 /* FLEXResources.h */,
|
||||
3A4C945A1B5B21410088C3F2 /* FLEXResources.m */,
|
||||
C37A0C91218BAC9600848CA7 /* FLEXObjcInternal.h */,
|
||||
C37A0C92218BAC9600848CA7 /* FLEXObjcInternal.mm */,
|
||||
3A4C945B1B5B21410088C3F2 /* FLEXRuntimeUtility.h */,
|
||||
3A4C945C1B5B21410088C3F2 /* FLEXRuntimeUtility.m */,
|
||||
3A4C945D1B5B21410088C3F2 /* FLEXUtility.h */,
|
||||
@@ -490,22 +555,15 @@
|
||||
path = ArgumentInputViews;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3A4C948E1B5B21410088C3F2 /* ExplorerToolbar */ = {
|
||||
3A4C948E1B5B21410088C3F2 /* Toolbar */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4C948F1B5B21410088C3F2 /* FLEXExplorerToolbar.h */,
|
||||
3A4C94901B5B21410088C3F2 /* FLEXExplorerToolbar.m */,
|
||||
3A4C94911B5B21410088C3F2 /* FLEXExplorerViewController.h */,
|
||||
3A4C94921B5B21410088C3F2 /* FLEXExplorerViewController.m */,
|
||||
3A4C94931B5B21410088C3F2 /* FLEXManager+Private.h */,
|
||||
3A4C94941B5B21410088C3F2 /* FLEXManager.h */,
|
||||
3A4C94951B5B21410088C3F2 /* FLEXManager.m */,
|
||||
3A4C94961B5B21410088C3F2 /* FLEXToolbarItem.h */,
|
||||
3A4C94971B5B21410088C3F2 /* FLEXToolbarItem.m */,
|
||||
3A4C94981B5B21410088C3F2 /* FLEXWindow.h */,
|
||||
3A4C94991B5B21410088C3F2 /* FLEXWindow.m */,
|
||||
94A515211C4CA2080063292F /* FLEXExplorerToolbar.h */,
|
||||
94A515221C4CA2080063292F /* FLEXExplorerToolbar.m */,
|
||||
94A515231C4CA2080063292F /* FLEXToolbarItem.h */,
|
||||
94A515241C4CA2080063292F /* FLEXToolbarItem.m */,
|
||||
);
|
||||
path = ExplorerToolbar;
|
||||
path = Toolbar;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3A4C949A1B5B21410088C3F2 /* GlobalStateExplorers */ = {
|
||||
@@ -524,6 +582,8 @@
|
||||
3A4C94A41B5B21410088C3F2 /* FLEXGlobalsTableViewController.m */,
|
||||
3A4C94A51B5B21410088C3F2 /* FLEXInstancesTableViewController.h */,
|
||||
3A4C94A61B5B21410088C3F2 /* FLEXInstancesTableViewController.m */,
|
||||
C3DB9F622107FC9600B46809 /* FLEXObjectRef.h */,
|
||||
C3DB9F632107FC9600B46809 /* FLEXObjectRef.m */,
|
||||
3A4C94A71B5B21410088C3F2 /* FLEXLibrariesTableViewController.h */,
|
||||
3A4C94A81B5B21410088C3F2 /* FLEXLibrariesTableViewController.m */,
|
||||
3A4C94A91B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.h */,
|
||||
@@ -565,6 +625,8 @@
|
||||
3A4C94BE1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.m */,
|
||||
3A4C94BF1B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.h */,
|
||||
3A4C94C01B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.m */,
|
||||
2EF6B04C1D494BE50006BDA5 /* FLEXNetworkCurlLogger.h */,
|
||||
2EF6B04B1D494BE50006BDA5 /* FLEXNetworkCurlLogger.m */,
|
||||
3A4C94C11B5B21410088C3F2 /* PonyDebugger */,
|
||||
);
|
||||
path = Network;
|
||||
@@ -592,8 +654,12 @@
|
||||
779B1EBF1C0C4D7C001F5E49 /* DatabaseBrowser */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
222C88211C7339DC007CA15F /* FLEXRealmDefines.h */,
|
||||
779B1EC01C0C4D7C001F5E49 /* FLEXDatabaseManager.h */,
|
||||
779B1EC11C0C4D7C001F5E49 /* FLEXDatabaseManager.m */,
|
||||
224D49A41C673AB5000EAB86 /* FLEXRealmDatabaseManager.h */,
|
||||
224D49A51C673AB5000EAB86 /* FLEXRealmDatabaseManager.m */,
|
||||
224D49A61C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.h */,
|
||||
224D49A71C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.m */,
|
||||
779B1EC21C0C4D7C001F5E49 /* FLEXMultiColumnTableView.h */,
|
||||
779B1EC31C0C4D7C001F5E49 /* FLEXMultiColumnTableView.m */,
|
||||
779B1EC41C0C4D7C001F5E49 /* FLEXTableColumnHeader.h */,
|
||||
@@ -611,6 +677,26 @@
|
||||
path = DatabaseBrowser;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94A515111C4C9C1B0063292F /* Manager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94A515161C4CA1D70063292F /* FLEXManager+Private.h */,
|
||||
94A515151C4CA1D70063292F /* FLEXManager.m */,
|
||||
);
|
||||
name = Manager;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94A515121C4C9E7B0063292F /* ExplorerInterface */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94A515191C4CA1F10063292F /* FLEXExplorerViewController.h */,
|
||||
94A5151A1C4CA1F10063292F /* FLEXExplorerViewController.m */,
|
||||
94A5151B1C4CA1F10063292F /* FLEXWindow.h */,
|
||||
94A5151C1C4CA1F10063292F /* FLEXWindow.m */,
|
||||
);
|
||||
name = ExplorerInterface;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@@ -624,14 +710,16 @@
|
||||
3A4C95381B5B21410088C3F2 /* FLEXNetworkRecorder.h in Headers */,
|
||||
3A4C94251B5B20570088C3F2 /* FLEX.h in Headers */,
|
||||
3A4C95051B5B21410088C3F2 /* FLEXArgumentInputViewFactory.h in Headers */,
|
||||
222C88221C7339DC007CA15F /* FLEXRealmDefines.h in Headers */,
|
||||
3A4C951E1B5B21410088C3F2 /* FLEXClassesTableViewController.h in Headers */,
|
||||
779B1ED21C0C4D7C001F5E49 /* FLEXTableColumnHeader.h in Headers */,
|
||||
3A4C94FD1B5B21410088C3F2 /* FLEXArgumentInputStructView.h in Headers */,
|
||||
94A515141C4CA1C00063292F /* FLEXManager.h in Headers */,
|
||||
3A4C95201B5B21410088C3F2 /* FLEXFileBrowserFileOperationController.h in Headers */,
|
||||
C37A0C93218BAC9600848CA7 /* FLEXObjcInternal.h in Headers */,
|
||||
3A4C953E1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.h in Headers */,
|
||||
3A4C95301B5B21410088C3F2 /* FLEXSystemLogMessage.h in Headers */,
|
||||
3A4C95361B5B21410088C3F2 /* FLEXNetworkHistoryTableViewController.h in Headers */,
|
||||
3A4C95131B5B21410088C3F2 /* FLEXExplorerToolbar.h in Headers */,
|
||||
3A4C94DD1B5B21410088C3F2 /* FLEXHeapEnumerator.h in Headers */,
|
||||
3A4C94DB1B5B21410088C3F2 /* FLEXViewExplorerViewController.h in Headers */,
|
||||
3A4C95321B5B21410088C3F2 /* FLEXSystemLogTableViewCell.h in Headers */,
|
||||
@@ -641,13 +729,12 @@
|
||||
3A4C94D11B5B21410088C3F2 /* FLEXLayerExplorerViewController.h in Headers */,
|
||||
779B1ED01C0C4D7C001F5E49 /* FLEXMultiColumnTableView.h in Headers */,
|
||||
3A4C94D31B5B21410088C3F2 /* FLEXObjectExplorerFactory.h in Headers */,
|
||||
94A515271C4CA2080063292F /* FLEXToolbarItem.h in Headers */,
|
||||
3A4C94E31B5B21410088C3F2 /* FLEXRuntimeUtility.h in Headers */,
|
||||
3A4C95341B5B21410088C3F2 /* FLEXSystemLogTableViewController.h in Headers */,
|
||||
3A4C951C1B5B21410088C3F2 /* FLEXWindow.h in Headers */,
|
||||
3A4C95091B5B21410088C3F2 /* FLEXFieldEditorView.h in Headers */,
|
||||
3A4C950D1B5B21410088C3F2 /* FLEXIvarEditorViewController.h in Headers */,
|
||||
3A4C95281B5B21410088C3F2 /* FLEXInstancesTableViewController.h in Headers */,
|
||||
3A4C95151B5B21410088C3F2 /* FLEXExplorerViewController.h in Headers */,
|
||||
3A4C950F1B5B21410088C3F2 /* FLEXMethodCallingViewController.h in Headers */,
|
||||
3A4C94F51B5B21410088C3F2 /* FLEXArgumentInputJSONObjectView.h in Headers */,
|
||||
3A4C94F11B5B21410088C3F2 /* FLEXArgumentInputFontsPickerView.h in Headers */,
|
||||
@@ -655,13 +742,14 @@
|
||||
3A4C94C91B5B21410088C3F2 /* FLEXDefaultsExplorerViewController.h in Headers */,
|
||||
3A4C95221B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.h in Headers */,
|
||||
3A4C94FF1B5B21410088C3F2 /* FLEXArgumentInputSwitchView.h in Headers */,
|
||||
3A4C95171B5B21410088C3F2 /* FLEXManager+Private.h in Headers */,
|
||||
3A4C94E71B5B21410088C3F2 /* FLEXHierarchyTableViewCell.h in Headers */,
|
||||
3A4C951A1B5B21410088C3F2 /* FLEXToolbarItem.h in Headers */,
|
||||
224D49AA1C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.h in Headers */,
|
||||
3A4C95031B5B21410088C3F2 /* FLEXArgumentInputView.h in Headers */,
|
||||
94A5151D1C4CA1F10063292F /* FLEXExplorerViewController.h in Headers */,
|
||||
3A4C94C51B5B21410088C3F2 /* FLEXArrayExplorerViewController.h in Headers */,
|
||||
3A4C94CB1B5B21410088C3F2 /* FLEXDictionaryExplorerViewController.h in Headers */,
|
||||
3A4C95071B5B21410088C3F2 /* FLEXDefaultEditorViewController.h in Headers */,
|
||||
94A5151F1C4CA1F10063292F /* FLEXWindow.h in Headers */,
|
||||
779B1ECE1C0C4D7C001F5E49 /* FLEXDatabaseManager.h in Headers */,
|
||||
3A4C94D51B5B21410088C3F2 /* FLEXObjectExplorerViewController.h in Headers */,
|
||||
3A4C95011B5B21410088C3F2 /* FLEXArgumentInputTextView.h in Headers */,
|
||||
@@ -673,24 +761,29 @@
|
||||
3A4C94F71B5B21410088C3F2 /* FLEXArgumentInputNotSupportedView.h in Headers */,
|
||||
3A4C94E51B5B21410088C3F2 /* FLEXUtility.h in Headers */,
|
||||
3A4C94CF1B5B21410088C3F2 /* FLEXImageExplorerViewController.h in Headers */,
|
||||
2EF6B04E1D494BE50006BDA5 /* FLEXNetworkCurlLogger.h in Headers */,
|
||||
3A4C950B1B5B21410088C3F2 /* FLEXFieldEditorViewController.h in Headers */,
|
||||
94A515251C4CA2080063292F /* FLEXExplorerToolbar.h in Headers */,
|
||||
3A4C953C1B5B21410088C3F2 /* FLEXNetworkTransaction.h in Headers */,
|
||||
3A4C94D71B5B21410088C3F2 /* FLEXSetExplorerViewController.h in Headers */,
|
||||
3A4C94D91B5B21410088C3F2 /* FLEXViewControllerExplorerViewController.h in Headers */,
|
||||
3A4C952E1B5B21410088C3F2 /* FLEXWebViewController.h in Headers */,
|
||||
3A4C95181B5B21410088C3F2 /* FLEXManager.h in Headers */,
|
||||
3A4C95111B5B21410088C3F2 /* FLEXPropertyEditorViewController.h in Headers */,
|
||||
3A4C94E91B5B21410088C3F2 /* FLEXHierarchyTableViewController.h in Headers */,
|
||||
3A4C94F31B5B21410088C3F2 /* FLEXArgumentInputFontView.h in Headers */,
|
||||
3A4C95261B5B21410088C3F2 /* FLEXGlobalsTableViewController.h in Headers */,
|
||||
224D49A81C673AB5000EAB86 /* FLEXRealmDatabaseManager.h in Headers */,
|
||||
3A4C94CD1B5B21410088C3F2 /* FLEXGlobalsTableViewControllerEntry.h in Headers */,
|
||||
3A4C94FB1B5B21410088C3F2 /* FLEXArgumentInputStringView.h in Headers */,
|
||||
3A4C95421B5B21410088C3F2 /* FLEXNetworkObserver.h in Headers */,
|
||||
679F64861BD53B7B00A8C94C /* FLEXCookiesTableViewController.h in Headers */,
|
||||
C3DB9F642107FC9600B46809 /* FLEXObjectRef.h in Headers */,
|
||||
3A4C95401B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.h in Headers */,
|
||||
3A4C95241B5B21410088C3F2 /* FLEXFileBrowserTableViewController.h in Headers */,
|
||||
94AAF0381BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.h in Headers */,
|
||||
94AAF03A1BAF2F0300DE8760 /* FLEXKeyboardShortcutManager.h in Headers */,
|
||||
C395D6D921789BD800BEAD4D /* FLEXColorExplorerViewController.h in Headers */,
|
||||
94A515181C4CA1D70063292F /* FLEXManager+Private.h in Headers */,
|
||||
3A4C94E11B5B21410088C3F2 /* FLEXResources.h in Headers */,
|
||||
779B1ED81C0C4D7C001F5E49 /* FLEXTableLeftCell.h in Headers */,
|
||||
);
|
||||
@@ -699,6 +792,24 @@
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
1C27A8B51F0E5A0300F0D02D /* FLEXTestsMethodsList */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1C27A8C01F0E5A0400F0D02D /* Build configuration list for PBXNativeTarget "FLEXTestsMethodsList" */;
|
||||
buildPhases = (
|
||||
1C27A8B21F0E5A0300F0D02D /* Sources */,
|
||||
1C27A8B31F0E5A0300F0D02D /* Frameworks */,
|
||||
1C27A8B41F0E5A0300F0D02D /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
1C27A8BD1F0E5A0400F0D02D /* PBXTargetDependency */,
|
||||
);
|
||||
name = FLEXTestsMethodsList;
|
||||
productName = FLEXTestsMethodsList;
|
||||
productReference = 1C27A8B61F0E5A0300F0D02D /* FLEXTestsMethodsList.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
3A4C941E1B5B20570088C3F2 /* FLEX */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 3A4C94351B5B20570088C3F2 /* Build configuration list for PBXNativeTarget "FLEX" */;
|
||||
@@ -724,9 +835,12 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
CLASSPREFIX = FLEX;
|
||||
LastUpgradeCheck = 0700;
|
||||
LastUpgradeCheck = 0930;
|
||||
ORGANIZATIONNAME = Flipboard;
|
||||
TargetAttributes = {
|
||||
1C27A8B51F0E5A0300F0D02D = {
|
||||
DevelopmentTeam = U3LST7M92S;
|
||||
};
|
||||
3A4C941E1B5B20570088C3F2 = {
|
||||
CreatedOnToolsVersion = 6.4;
|
||||
};
|
||||
@@ -745,11 +859,19 @@
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
3A4C941E1B5B20570088C3F2 /* FLEX */,
|
||||
1C27A8B51F0E5A0300F0D02D /* FLEXTestsMethodsList */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
1C27A8B41F0E5A0300F0D02D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
3A4C941D1B5B20570088C3F2 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -761,11 +883,22 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
1C27A8B21F0E5A0300F0D02D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1C27A8B91F0E5A0400F0D02D /* FLEXTestsMethodsList.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
3A4C941A1B5B20570088C3F2 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
942DCD871BAE0CA300DB5DC2 /* FLEXKeyboardShortcutManager.m in Sources */,
|
||||
224D49A91C673AB5000EAB86 /* FLEXRealmDatabaseManager.m in Sources */,
|
||||
2EF6B04D1D494BE50006BDA5 /* FLEXNetworkCurlLogger.m in Sources */,
|
||||
94A515201C4CA1F10063292F /* FLEXWindow.m in Sources */,
|
||||
3A4C95121B5B21410088C3F2 /* FLEXPropertyEditorViewController.m in Sources */,
|
||||
3A4C95391B5B21410088C3F2 /* FLEXNetworkRecorder.m in Sources */,
|
||||
3A4C950E1B5B21410088C3F2 /* FLEXIvarEditorViewController.m in Sources */,
|
||||
@@ -791,10 +924,10 @@
|
||||
779B1EDB1C0C4D7C001F5E49 /* FLEXTableListViewController.m in Sources */,
|
||||
3A4C94E41B5B21410088C3F2 /* FLEXRuntimeUtility.m in Sources */,
|
||||
3A4C94D41B5B21410088C3F2 /* FLEXObjectExplorerFactory.m in Sources */,
|
||||
94A515171C4CA1D70063292F /* FLEXManager.m in Sources */,
|
||||
3A4C952F1B5B21410088C3F2 /* FLEXWebViewController.m in Sources */,
|
||||
3A4C94DC1B5B21410088C3F2 /* FLEXViewExplorerViewController.m in Sources */,
|
||||
3A4C95041B5B21410088C3F2 /* FLEXArgumentInputView.m in Sources */,
|
||||
3A4C951B1B5B21410088C3F2 /* FLEXToolbarItem.m in Sources */,
|
||||
3A4C95411B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.m in Sources */,
|
||||
3A4C94D61B5B21410088C3F2 /* FLEXObjectExplorerViewController.m in Sources */,
|
||||
3A4C95211B5B21410088C3F2 /* FLEXFileBrowserFileOperationController.m in Sources */,
|
||||
@@ -803,6 +936,7 @@
|
||||
3A4C94DA1B5B21410088C3F2 /* FLEXViewControllerExplorerViewController.m in Sources */,
|
||||
779B1ED51C0C4D7C001F5E49 /* FLEXTableContentCell.m in Sources */,
|
||||
3A4C94E21B5B21410088C3F2 /* FLEXResources.m in Sources */,
|
||||
94A515281C4CA2080063292F /* FLEXToolbarItem.m in Sources */,
|
||||
3A4C94D81B5B21410088C3F2 /* FLEXSetExplorerViewController.m in Sources */,
|
||||
3A4C95311B5B21410088C3F2 /* FLEXSystemLogMessage.m in Sources */,
|
||||
3A4C94F41B5B21410088C3F2 /* FLEXArgumentInputFontView.m in Sources */,
|
||||
@@ -811,39 +945,79 @@
|
||||
3A4C94F81B5B21410088C3F2 /* FLEXArgumentInputNotSupportedView.m in Sources */,
|
||||
3A4C95351B5B21410088C3F2 /* FLEXSystemLogTableViewController.m in Sources */,
|
||||
3A4C95271B5B21410088C3F2 /* FLEXGlobalsTableViewController.m in Sources */,
|
||||
3A4C95161B5B21410088C3F2 /* FLEXExplorerViewController.m in Sources */,
|
||||
779B1ED31C0C4D7C001F5E49 /* FLEXTableColumnHeader.m in Sources */,
|
||||
C37A0C94218BAC9600848CA7 /* FLEXObjcInternal.mm in Sources */,
|
||||
3A4C94EA1B5B21410088C3F2 /* FLEXHierarchyTableViewController.m in Sources */,
|
||||
3A4C95331B5B21410088C3F2 /* FLEXSystemLogTableViewCell.m in Sources */,
|
||||
3A4C95191B5B21410088C3F2 /* FLEXManager.m in Sources */,
|
||||
C3DB9F652107FC9600B46809 /* FLEXObjectRef.m in Sources */,
|
||||
3A4C95021B5B21410088C3F2 /* FLEXArgumentInputTextView.m in Sources */,
|
||||
94A515261C4CA2080063292F /* FLEXExplorerToolbar.m in Sources */,
|
||||
3A4C94FA1B5B21410088C3F2 /* FLEXArgumentInputNumberView.m in Sources */,
|
||||
779B1ED71C0C4D7C001F5E49 /* FLEXTableContentViewController.m in Sources */,
|
||||
C395D6DA21789BD800BEAD4D /* FLEXColorExplorerViewController.m in Sources */,
|
||||
3A4C95001B5B21410088C3F2 /* FLEXArgumentInputSwitchView.m in Sources */,
|
||||
3A4C94CC1B5B21410088C3F2 /* FLEXDictionaryExplorerViewController.m in Sources */,
|
||||
3A4C953F1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.m in Sources */,
|
||||
224D49AB1C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.m in Sources */,
|
||||
779B1ED91C0C4D7C001F5E49 /* FLEXTableLeftCell.m in Sources */,
|
||||
779B1ECF1C0C4D7C001F5E49 /* FLEXDatabaseManager.m in Sources */,
|
||||
3A4C94E61B5B21410088C3F2 /* FLEXUtility.m in Sources */,
|
||||
3A4C95231B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.m in Sources */,
|
||||
3A4C950C1B5B21410088C3F2 /* FLEXFieldEditorViewController.m in Sources */,
|
||||
3A4C952D1B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.m in Sources */,
|
||||
3A4C953D1B5B21410088C3F2 /* FLEXNetworkTransaction.m in Sources */,
|
||||
3A4C95141B5B21410088C3F2 /* FLEXExplorerToolbar.m in Sources */,
|
||||
3A4C94E81B5B21410088C3F2 /* FLEXHierarchyTableViewCell.m in Sources */,
|
||||
3A4C94C81B5B21410088C3F2 /* FLEXClassExplorerViewController.m in Sources */,
|
||||
3A4C950A1B5B21410088C3F2 /* FLEXFieldEditorView.m in Sources */,
|
||||
3A4C951D1B5B21410088C3F2 /* FLEXWindow.m in Sources */,
|
||||
3A4C95061B5B21410088C3F2 /* FLEXArgumentInputViewFactory.m in Sources */,
|
||||
3A4C95291B5B21410088C3F2 /* FLEXInstancesTableViewController.m in Sources */,
|
||||
3A4C952B1B5B21410088C3F2 /* FLEXLibrariesTableViewController.m in Sources */,
|
||||
94A5151E1C4CA1F10063292F /* FLEXExplorerViewController.m in Sources */,
|
||||
3A4C95371B5B21410088C3F2 /* FLEXNetworkHistoryTableViewController.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
1C27A8BD1F0E5A0400F0D02D /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 3A4C941E1B5B20570088C3F2 /* FLEX */;
|
||||
targetProxy = 1C27A8BC1F0E5A0400F0D02D /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
1C27A8BE1F0E5A0400F0D02D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = U3LST7M92S;
|
||||
INFOPLIST_FILE = FLEXTestsMethodsList/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.flipboard.FLEXTestsMethodsList;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1C27A8BF1F0E5A0400F0D02D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
DEVELOPMENT_TEAM = U3LST7M92S;
|
||||
INFOPLIST_FILE = FLEXTestsMethodsList/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.flipboard.FLEXTestsMethodsList;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
3A4C94331B5B20570088C3F2 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -852,13 +1026,23 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -885,6 +1069,7 @@
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
@@ -900,13 +1085,23 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -925,6 +1120,7 @@
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_LDFLAGS = "";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
@@ -936,10 +1132,15 @@
|
||||
3A4C94361B5B20570088C3F2 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = Classes/Info.plist;
|
||||
INSTALL_PATH = "@rpath";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
@@ -952,10 +1153,15 @@
|
||||
3A4C94371B5B20570088C3F2 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = Classes/Info.plist;
|
||||
INSTALL_PATH = "@rpath";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
@@ -968,6 +1174,15 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
1C27A8C01F0E5A0400F0D02D /* Build configuration list for PBXNativeTarget "FLEXTestsMethodsList" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1C27A8BE1F0E5A0400F0D02D /* Debug */,
|
||||
1C27A8BF1F0E5A0400F0D02D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
3A4C94191B5B20570088C3F2 /* Build configuration list for PBXProject "FLEX" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0700"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,413 +0,0 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3A4C94251B5B20570088C3F2 /* FLEX.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94241B5B20570088C3F2 /* FLEX.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
3A4C942B1B5B20570088C3F2 /* FLEX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4C941F1B5B20570088C3F2 /* FLEX.framework */; };
|
||||
3A4C94321B5B20570088C3F2 /* FLEXTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94311B5B20570088C3F2 /* FLEXTests.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
3A4C942C1B5B20570088C3F2 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 3A4C94161B5B20570088C3F2 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 3A4C941E1B5B20570088C3F2;
|
||||
remoteInfo = FLEX;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
3A4C941F1B5B20570088C3F2 /* FLEX.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FLEX.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3A4C94231B5B20570088C3F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
3A4C94241B5B20570088C3F2 /* FLEX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEX.h; sourceTree = "<group>"; };
|
||||
3A4C942A1B5B20570088C3F2 /* FLEXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FLEXTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3A4C94301B5B20570088C3F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
3A4C94311B5B20570088C3F2 /* FLEXTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXTests.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
3A4C941B1B5B20570088C3F2 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
3A4C94271B5B20570088C3F2 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3A4C942B1B5B20570088C3F2 /* FLEX.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
3A4C94151B5B20570088C3F2 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4C94211B5B20570088C3F2 /* FLEX */,
|
||||
3A4C942E1B5B20570088C3F2 /* FLEXTests */,
|
||||
3A4C94201B5B20570088C3F2 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3A4C94201B5B20570088C3F2 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4C941F1B5B20570088C3F2 /* FLEX.framework */,
|
||||
3A4C942A1B5B20570088C3F2 /* FLEXTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3A4C94211B5B20570088C3F2 /* FLEX */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4C94241B5B20570088C3F2 /* FLEX.h */,
|
||||
3A4C94221B5B20570088C3F2 /* Supporting Files */,
|
||||
);
|
||||
path = FLEX;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3A4C94221B5B20570088C3F2 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4C94231B5B20570088C3F2 /* Info.plist */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3A4C942E1B5B20570088C3F2 /* FLEXTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4C94311B5B20570088C3F2 /* FLEXTests.m */,
|
||||
3A4C942F1B5B20570088C3F2 /* Supporting Files */,
|
||||
);
|
||||
path = FLEXTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3A4C942F1B5B20570088C3F2 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4C94301B5B20570088C3F2 /* Info.plist */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
3A4C941C1B5B20570088C3F2 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3A4C94251B5B20570088C3F2 /* FLEX.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
3A4C941E1B5B20570088C3F2 /* FLEX */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 3A4C94351B5B20570088C3F2 /* Build configuration list for PBXNativeTarget "FLEX" */;
|
||||
buildPhases = (
|
||||
3A4C941A1B5B20570088C3F2 /* Sources */,
|
||||
3A4C941B1B5B20570088C3F2 /* Frameworks */,
|
||||
3A4C941C1B5B20570088C3F2 /* Headers */,
|
||||
3A4C941D1B5B20570088C3F2 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = FLEX;
|
||||
productName = FLEX;
|
||||
productReference = 3A4C941F1B5B20570088C3F2 /* FLEX.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
3A4C94291B5B20570088C3F2 /* FLEXTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 3A4C94381B5B20570088C3F2 /* Build configuration list for PBXNativeTarget "FLEXTests" */;
|
||||
buildPhases = (
|
||||
3A4C94261B5B20570088C3F2 /* Sources */,
|
||||
3A4C94271B5B20570088C3F2 /* Frameworks */,
|
||||
3A4C94281B5B20570088C3F2 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
3A4C942D1B5B20570088C3F2 /* PBXTargetDependency */,
|
||||
);
|
||||
name = FLEXTests;
|
||||
productName = FLEXTests;
|
||||
productReference = 3A4C942A1B5B20570088C3F2 /* FLEXTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
3A4C94161B5B20570088C3F2 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0640;
|
||||
ORGANIZATIONNAME = Flipboard;
|
||||
TargetAttributes = {
|
||||
3A4C941E1B5B20570088C3F2 = {
|
||||
CreatedOnToolsVersion = 6.4;
|
||||
};
|
||||
3A4C94291B5B20570088C3F2 = {
|
||||
CreatedOnToolsVersion = 6.4;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 3A4C94191B5B20570088C3F2 /* Build configuration list for PBXProject "FLEX" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 3A4C94151B5B20570088C3F2;
|
||||
productRefGroup = 3A4C94201B5B20570088C3F2 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
3A4C941E1B5B20570088C3F2 /* FLEX */,
|
||||
3A4C94291B5B20570088C3F2 /* FLEXTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
3A4C941D1B5B20570088C3F2 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
3A4C94281B5B20570088C3F2 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
3A4C941A1B5B20570088C3F2 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
3A4C94261B5B20570088C3F2 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3A4C94321B5B20570088C3F2 /* FLEXTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
3A4C942D1B5B20570088C3F2 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 3A4C941E1B5B20570088C3F2 /* FLEX */;
|
||||
targetProxy = 3A4C942C1B5B20570088C3F2 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
3A4C94331B5B20570088C3F2 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
3A4C94341B5B20570088C3F2 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
3A4C94361B5B20570088C3F2 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = FLEX/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
3A4C94371B5B20570088C3F2 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = FLEX/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
3A4C94391B5B20570088C3F2 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = FLEXTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
3A4C943A1B5B20570088C3F2 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = FLEXTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
3A4C94191B5B20570088C3F2 /* Build configuration list for PBXProject "FLEX" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
3A4C94331B5B20570088C3F2 /* Debug */,
|
||||
3A4C94341B5B20570088C3F2 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
3A4C94351B5B20570088C3F2 /* Build configuration list for PBXNativeTarget "FLEX" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
3A4C94361B5B20570088C3F2 /* Debug */,
|
||||
3A4C94371B5B20570088C3F2 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
};
|
||||
3A4C94381B5B20570088C3F2 /* Build configuration list for PBXNativeTarget "FLEXTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
3A4C94391B5B20570088C3F2 /* Debug */,
|
||||
3A4C943A1B5B20570088C3F2 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 3A4C94161B5B20570088C3F2 /* Project object */;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:FLEX.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user