Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c761865b9b | |||
| 700c50af5d | |||
| b38cca06b1 | |||
| 6429573918 | |||
| f77f5ccdc9 | |||
| 7aeddcdb2c | |||
| a25ef87a51 | |||
| fbeb1beca0 | |||
| 059bde9711 | |||
| 2ca563f570 | |||
| 88c7ca9373 | |||
| 83486641aa | |||
| 6bd0c87881 | |||
| 1a64da70c9 | |||
| 87ea2bb147 | |||
| d9e9be53d8 | |||
| 142f037497 | |||
| 6cdb626d78 | |||
| 6e81029b8b | |||
| 1c7048e710 |
@@ -8,7 +8,7 @@
|
||||
|
||||
#import "FLEXFilteringTableViewController.h"
|
||||
#import "FLEXTableViewSection.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
|
||||
@interface FLEXFilteringTableViewController ()
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
|
||||
@property (nonatomic) BOOL showsShareToolbarItem;
|
||||
/// Called when the share button is pressed.
|
||||
/// Default implementation does nothign. Subclasses may override.
|
||||
- (void)shareButtonPressed;
|
||||
- (void)shareButtonPressed:(UIBarButtonItem *)sender;
|
||||
|
||||
/// Subclasses may call this to opt-out of all toolbar related behavior.
|
||||
/// This is necessary if you want to disable the gesture which reveals the toolbar.
|
||||
|
||||
@@ -222,7 +222,7 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
|
||||
self.tableView.dataSource = self;
|
||||
self.tableView.delegate = self;
|
||||
|
||||
_shareToolbarItem = FLEXBarButtonItemSystem(Action, self, @selector(shareButtonPressed));
|
||||
_shareToolbarItem = FLEXBarButtonItemSystem(Action, self, @selector(shareButtonPressed:));
|
||||
_bookmarksToolbarItem = [UIBarButtonItem
|
||||
itemWithImage:FLEXResources.bookmarksIcon target:self action:@selector(showBookmarks)
|
||||
];
|
||||
@@ -386,7 +386,7 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
|
||||
[self setupToolbarItems];
|
||||
}
|
||||
|
||||
- (void)shareButtonPressed {
|
||||
- (void)shareButtonPressed:(UIBarButtonItem *)sender {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "FLEXMacros.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
@class FLEXTableView;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
- (void)setupEditingBarItems {
|
||||
self.navigationItem.rightBarButtonItem = nil;
|
||||
self.toolbarItems = @[
|
||||
[UIBarButtonItem itemWithTitle:@"Close All" target:self action:@selector(closeAllButtonPressed)],
|
||||
[UIBarButtonItem itemWithTitle:@"Close All" target:self action:@selector(closeAllButtonPressed:)],
|
||||
UIBarButtonItem.flex_flexibleSpace,
|
||||
// We use a non-system done item because we change its title dynamically
|
||||
[UIBarButtonItem doneStyleitemWithTitle:@"Done" target:self action:@selector(toggleEditing)]
|
||||
@@ -149,7 +149,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)closeAllButtonPressed {
|
||||
- (void)closeAllButtonPressed:(UIBarButtonItem *)sender {
|
||||
[FLEXAlert makeSheet:^(FLEXAlert *make) {
|
||||
NSInteger count = self.bookmarks.count;
|
||||
NSString *title = FLEXPluralFormatString(count, @"Remove %@ bookmarks", @"Remove %@ bookmark");
|
||||
@@ -158,7 +158,7 @@
|
||||
[self toggleEditing];
|
||||
});
|
||||
make.button(@"Cancel").cancelStyle();
|
||||
} showFrom:self];
|
||||
} showFrom:self source:sender];
|
||||
}
|
||||
|
||||
- (void)closeAll {
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
[super viewDidLoad];
|
||||
|
||||
self.title = @"View Controllers at Tap";
|
||||
self.showsSearchBar = YES;
|
||||
[self disableToolbar];
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
self.toolbarItems = @[
|
||||
UIBarButtonItem.flex_fixedSpace,
|
||||
UIBarButtonItem.flex_flexibleSpace,
|
||||
FLEXBarButtonItemSystem(Add, self, @selector(addTabButtonPressed)),
|
||||
FLEXBarButtonItemSystem(Add, self, @selector(addTabButtonPressed:)),
|
||||
UIBarButtonItem.flex_flexibleSpace,
|
||||
FLEXBarButtonItemSystem(Edit, self, @selector(toggleEditing)),
|
||||
];
|
||||
@@ -121,7 +121,7 @@
|
||||
- (void)setupEditingBarItems {
|
||||
self.navigationItem.rightBarButtonItem = nil;
|
||||
self.toolbarItems = @[
|
||||
[UIBarButtonItem itemWithTitle:@"Close All" target:self action:@selector(closeAllButtonPressed)],
|
||||
[UIBarButtonItem itemWithTitle:@"Close All" target:self action:@selector(closeAllButtonPressed:)],
|
||||
UIBarButtonItem.flex_flexibleSpace,
|
||||
[UIBarButtonItem disabledSystemItem:UIBarButtonSystemItemAdd],
|
||||
UIBarButtonItem.flex_flexibleSpace,
|
||||
@@ -193,7 +193,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addTabButtonPressed {
|
||||
- (void)addTabButtonPressed:(UIBarButtonItem *)sender {
|
||||
if (FLEXBookmarkManager.bookmarks.count) {
|
||||
[FLEXAlert makeSheet:^(FLEXAlert *make) {
|
||||
make.title(@"New Tab");
|
||||
@@ -208,7 +208,7 @@
|
||||
] animated:YES completion:nil];
|
||||
});
|
||||
make.button(@"Cancel").cancelStyle();
|
||||
} showFrom:self];
|
||||
} showFrom:self source:sender];
|
||||
} else {
|
||||
// No bookmarks, just open the main menu
|
||||
[self addTabAndDismiss:[FLEXNavigationController
|
||||
@@ -224,7 +224,7 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)closeAllButtonPressed {
|
||||
- (void)closeAllButtonPressed:(UIBarButtonItem *)sender {
|
||||
[FLEXAlert makeSheet:^(FLEXAlert *make) {
|
||||
NSInteger count = self.openTabs.count;
|
||||
NSString *title = FLEXPluralFormatString(count, @"Close %@ tabs", @"Close %@ tab");
|
||||
@@ -233,7 +233,7 @@
|
||||
[self toggleEditing];
|
||||
});
|
||||
make.button(@"Cancel").cancelStyle();
|
||||
} showFrom:self];
|
||||
} showFrom:self source:sender];
|
||||
}
|
||||
|
||||
- (void)closeAll {
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
#import <FLEX/UIMenu+FLEX.h>
|
||||
#import <FLEX/UITextField+Range.h>
|
||||
|
||||
#import <FLEX/NSObject+Reflection.h>
|
||||
#import <FLEX/NSArray+Functional.h>
|
||||
#import <FLEX/NSObject+FLEX_Reflection.h>
|
||||
#import <FLEX/NSArray+FLEX.h>
|
||||
#import <FLEX/NSDictionary+ObjcRuntime.h>
|
||||
#import <FLEX/NSString+ObjcRuntime.h>
|
||||
#import <FLEX/NSString+FLEX.h>
|
||||
#import <FLEX/NSUserDefaults+FLEX.h>
|
||||
#import <FLEX/NSMapTable+FLEX_Subscripting.h>
|
||||
#import <FLEX/NSTimer+Blocks.h>
|
||||
#import <FLEX/NSTimer+FLEX.h>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#import "FLEXDBQueryRowCell.h"
|
||||
#import "FLEXMultiColumnTableView.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "UIFont+FLEX.h"
|
||||
#import "FLEXColor.h"
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FLEXSQLResult.h"
|
||||
|
||||
/// Conformers should automatically open and close the database
|
||||
@protocol FLEXDatabaseManager <NSObject>
|
||||
|
||||
@required
|
||||
|
||||
/// @return \c nil if the database couldn't be opened
|
||||
+ (instancetype)managerForDatabase:(NSString *)path;
|
||||
|
||||
- (BOOL)open;
|
||||
|
||||
/// @return a list of all table names
|
||||
- (NSArray<NSString *> *)queryAllTables;
|
||||
- (NSArray<NSString *> *)queryAllColumnsOfTable:(NSString *)tableName;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#import "FLEXRealmDatabaseManager.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "FLEXSQLResult.h"
|
||||
|
||||
#if __has_include(<Realm/Realm.h>)
|
||||
@@ -20,7 +20,7 @@
|
||||
@interface FLEXRealmDatabaseManager ()
|
||||
|
||||
@property (nonatomic, copy) NSString *path;
|
||||
@property (nonatomic) RLMRealm * realm;
|
||||
@property (nonatomic) RLMRealm *realm;
|
||||
|
||||
@end
|
||||
|
||||
@@ -43,6 +43,10 @@ static Class RLMRealmClass = nil;
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_path = path;
|
||||
|
||||
if (![self open]) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -14,6 +14,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// Describes the result of a non-select query, or an error of any kind of query
|
||||
+ (instancetype)message:(NSString *)message;
|
||||
/// Describes the result of a known failed execution
|
||||
+ (instancetype)error:(NSString *)message;
|
||||
|
||||
/// @param rowData A list of rows, where each element in the row
|
||||
/// corresponds to the column given in /c columnNames
|
||||
+ (instancetype)columns:(NSArray<NSString *> *)columnNames
|
||||
@@ -21,6 +24,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@property (nonatomic, readonly, nullable) NSString *message;
|
||||
|
||||
/// A value of YES means this is surely an error,
|
||||
/// but it still might be an error even with a value of NO
|
||||
@property (nonatomic, readonly) BOOL isError;
|
||||
|
||||
/// A list of column names
|
||||
@property (nonatomic, readonly, nullable) NSArray<NSString *> *columns;
|
||||
/// A list of rows, where each element in the row corresponds
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#import "FLEXSQLResult.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
|
||||
@implementation FLEXSQLResult
|
||||
@synthesize keyedRows = _keyedRows;
|
||||
@@ -16,6 +16,12 @@
|
||||
return [[self alloc] initWithmessage:message columns:nil rows:nil];
|
||||
}
|
||||
|
||||
+ (instancetype)error:(NSString *)message {
|
||||
FLEXSQLResult *result = [self message:message];
|
||||
result->_isError = YES;
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (instancetype)columns:(NSArray<NSString *> *)columnNames rows:(NSArray<NSArray<NSString *> *> *)rowData {
|
||||
return [[self alloc] initWithmessage:nil columns:columnNames rows:rowData];
|
||||
}
|
||||
|
||||
@@ -13,7 +13,20 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FLEXDatabaseManager.h"
|
||||
#import "FLEXSQLResult.h"
|
||||
|
||||
@interface FLEXSQLiteDatabaseManager : NSObject <FLEXDatabaseManager>
|
||||
|
||||
/// Contains the result of the last operation, which may be an error
|
||||
@property (nonatomic, readonly) FLEXSQLResult *lastResult;
|
||||
/// Calls into \c sqlite3_last_insert_rowid()
|
||||
@property (nonatomic, readonly) NSInteger lastRowID;
|
||||
|
||||
/// Given a statement like 'SELECT * from @table where @col = @val' and arguments
|
||||
/// like { @"table": @"Album", @"col": @"year", @"val" @1 } this method will
|
||||
/// invoke the statement and properly bind the given arguments to the statement.
|
||||
///
|
||||
/// You may pass NSStrings, NSData, NSNumbers, or NSNulls as values.
|
||||
- (FLEXSQLResult *)executeStatement:(NSString *)statement arguments:(NSDictionary<NSString *, id> *)args;
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
#import "FLEXSQLiteDatabaseManager.h"
|
||||
#import "FLEXManager.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "FLEXSQLResult.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "FLEXRuntimeConstants.h"
|
||||
#import <sqlite3.h>
|
||||
|
||||
static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
|
||||
@@ -36,6 +36,10 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self close];
|
||||
}
|
||||
|
||||
- (BOOL)open {
|
||||
if (self.db) {
|
||||
return YES;
|
||||
@@ -52,8 +56,7 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
|
||||
#endif
|
||||
|
||||
if (err != SQLITE_OK) {
|
||||
NSLog(@"error opening!: %d", err);
|
||||
return NO;
|
||||
return [self storeErrorForLastTask:@"Open"];
|
||||
}
|
||||
|
||||
return YES;
|
||||
@@ -81,7 +84,9 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
|
||||
}
|
||||
}
|
||||
} else if (SQLITE_OK != rc) {
|
||||
NSLog(@"error closing!: %d", rc);
|
||||
[self storeErrorForLastTask:@"Close"];
|
||||
self.db = nil;
|
||||
return NO;
|
||||
}
|
||||
} while (retry);
|
||||
|
||||
@@ -89,6 +94,10 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSInteger)lastRowID {
|
||||
return (NSInteger)sqlite3_last_insert_rowid(self.db);
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)queryAllTables {
|
||||
return [[self executeStatement:QUERY_TABLENAMES].rows flex_mapped:^id(NSArray *table, NSUInteger idx) {
|
||||
return table.firstObject;
|
||||
@@ -111,14 +120,24 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
|
||||
}
|
||||
|
||||
- (FLEXSQLResult *)executeStatement:(NSString *)sql {
|
||||
return [self executeStatement:sql arguments:nil];
|
||||
}
|
||||
|
||||
- (FLEXSQLResult *)executeStatement:(NSString *)sql arguments:(NSDictionary *)args {
|
||||
[self open];
|
||||
|
||||
FLEXSQLResult *result = nil;
|
||||
|
||||
sqlite3_stmt *pstmt;
|
||||
if (sqlite3_prepare_v2(_db, sql.UTF8String, -1, &pstmt, 0) == SQLITE_OK) {
|
||||
int status;
|
||||
if ((status = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &pstmt, 0)) == SQLITE_OK) {
|
||||
NSMutableArray<NSArray *> *rows = [NSMutableArray new];
|
||||
|
||||
// Bind parameters, if any
|
||||
if (![self bindParameters:args toStatement:pstmt]) {
|
||||
return self.lastResult;
|
||||
}
|
||||
|
||||
// Grab columns
|
||||
int columnCount = sqlite3_column_count(pstmt);
|
||||
NSArray<NSString *> *columns = [NSArray flex_forEachUpTo:columnCount map:^id(NSUInteger i) {
|
||||
@@ -126,7 +145,6 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
|
||||
}];
|
||||
|
||||
// Execute statement
|
||||
int status;
|
||||
while ((status = sqlite3_step(pstmt)) == SQLITE_ROW) {
|
||||
// Grab rows if this is a selection query
|
||||
int dataCount = sqlite3_data_count(pstmt);
|
||||
@@ -140,30 +158,111 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
|
||||
if (status == SQLITE_DONE) {
|
||||
if (rows.count) {
|
||||
// We selected some rows
|
||||
result = [FLEXSQLResult columns:columns rows:rows];
|
||||
result = _lastResult = [FLEXSQLResult columns:columns rows:rows];
|
||||
} else {
|
||||
// We executed a query like INSERT, UDPATE, or DELETE
|
||||
int rowsAffected = sqlite3_changes(_db);
|
||||
NSString *message = [NSString stringWithFormat:@"%d row(s) affected", rowsAffected];
|
||||
result = [FLEXSQLResult message:message];
|
||||
result = _lastResult = [FLEXSQLResult message:message];
|
||||
}
|
||||
} else {
|
||||
// An error occured executing the query
|
||||
result = [FLEXSQLResult message:@(sqlite3_errmsg(_db) ?: "(Execution: empty error)")];
|
||||
result = _lastResult = [self errorResult:@"Execution"];
|
||||
}
|
||||
} else {
|
||||
// An error occurred creating the prepared statement
|
||||
result = [FLEXSQLResult message:@(sqlite3_errmsg(_db) ?: "(Prepared statement: empty error)")];
|
||||
result = _lastResult = [self errorResult:@"Prepared statement"];
|
||||
}
|
||||
|
||||
sqlite3_finalize(pstmt);
|
||||
[self close];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
/// @return YES on success, NO if an error was encountered and stored in \c lastResult
|
||||
- (BOOL)bindParameters:(NSDictionary *)args toStatement:(sqlite3_stmt *)pstmt {
|
||||
for (NSString *param in args.allKeys) {
|
||||
int status = SQLITE_OK, idx = sqlite3_bind_parameter_index(pstmt, param.UTF8String);
|
||||
id value = args[param];
|
||||
|
||||
if (idx == 0) {
|
||||
// No parameter matching that arg
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
|
||||
// Null
|
||||
if ([value isKindOfClass:[NSNull class]]) {
|
||||
status = sqlite3_bind_null(pstmt, idx);
|
||||
}
|
||||
// String params
|
||||
else if ([value isKindOfClass:[NSString class]]) {
|
||||
const char *str = [value UTF8String];
|
||||
status = sqlite3_bind_text(pstmt, idx, str, (int)strlen(str), SQLITE_TRANSIENT);
|
||||
}
|
||||
// Data params
|
||||
else if ([value isKindOfClass:[NSData class]]) {
|
||||
const void *blob = [value bytes];
|
||||
status = sqlite3_bind_blob64(pstmt, idx, blob, [value length], SQLITE_TRANSIENT);
|
||||
}
|
||||
// Primitive params
|
||||
else if ([value isKindOfClass:[NSNumber class]]) {
|
||||
FLEXTypeEncoding type = [value objCType][0];
|
||||
switch (type) {
|
||||
case FLEXTypeEncodingCBool:
|
||||
case FLEXTypeEncodingChar:
|
||||
case FLEXTypeEncodingUnsignedChar:
|
||||
case FLEXTypeEncodingShort:
|
||||
case FLEXTypeEncodingUnsignedShort:
|
||||
case FLEXTypeEncodingInt:
|
||||
case FLEXTypeEncodingUnsignedInt:
|
||||
case FLEXTypeEncodingLong:
|
||||
case FLEXTypeEncodingUnsignedLong:
|
||||
case FLEXTypeEncodingLongLong:
|
||||
case FLEXTypeEncodingUnsignedLongLong:
|
||||
status = sqlite3_bind_int64(pstmt, idx, (sqlite3_int64)[value longValue]);
|
||||
break;
|
||||
|
||||
case FLEXTypeEncodingFloat:
|
||||
case FLEXTypeEncodingDouble:
|
||||
status = sqlite3_bind_double(pstmt, idx, [value doubleValue]);
|
||||
break;
|
||||
|
||||
default:
|
||||
@throw NSInternalInconsistencyException;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Unsupported type
|
||||
else {
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
|
||||
if (status != SQLITE_OK) {
|
||||
return [self storeErrorForLastTask:
|
||||
[NSString stringWithFormat:@"Binding param named '%@'", param]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)storeErrorForLastTask:(NSString *)action {
|
||||
_lastResult = [self errorResult:action];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (FLEXSQLResult *)errorResult:(NSString *)description {
|
||||
const char *error = sqlite3_errmsg(_db);
|
||||
NSString *message = error ? @(error) : [NSString
|
||||
stringWithFormat:@"(%@: empty error", description
|
||||
];
|
||||
|
||||
return [FLEXSQLResult error:message];
|
||||
}
|
||||
|
||||
- (id)objectForColumnIndex:(int)columnIdx stmt:(sqlite3_stmt*)stmt {
|
||||
int columnType = sqlite3_column_type(stmt, columnIdx);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#import "FLEXRealmDatabaseManager.h"
|
||||
#import "FLEXTableContentViewController.h"
|
||||
#import "FLEXMutableListSection.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "FLEXAlert.h"
|
||||
|
||||
@interface FLEXTableListViewController ()
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// FLEXCookiesTableViewController.h
|
||||
// FLEXCookiesViewController.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Rich Robinson on 19/10/2015.
|
||||
@@ -9,6 +9,6 @@
|
||||
#import "FLEXGlobalsEntry.h"
|
||||
#import "FLEXFilteringTableViewController.h"
|
||||
|
||||
@interface FLEXCookiesTableViewController : FLEXFilteringTableViewController <FLEXGlobalsEntry>
|
||||
@interface FLEXCookiesViewController : FLEXFilteringTableViewController <FLEXGlobalsEntry>
|
||||
|
||||
@end
|
||||
+4
-4
@@ -1,22 +1,22 @@
|
||||
//
|
||||
// FLEXCookiesTableViewController.m
|
||||
// FLEXCookiesViewController.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Rich Robinson on 19/10/2015.
|
||||
// Copyright © 2015 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXCookiesTableViewController.h"
|
||||
#import "FLEXCookiesViewController.h"
|
||||
#import "FLEXObjectExplorerFactory.h"
|
||||
#import "FLEXMutableListSection.h"
|
||||
#import "FLEXUtility.h"
|
||||
|
||||
@interface FLEXCookiesTableViewController ()
|
||||
@interface FLEXCookiesViewController ()
|
||||
@property (nonatomic, readonly) FLEXMutableListSection<NSHTTPCookie *> *cookies;
|
||||
@property (nonatomic) NSString *headerTitle;
|
||||
@end
|
||||
|
||||
@implementation FLEXCookiesTableViewController
|
||||
@implementation FLEXCookiesViewController
|
||||
|
||||
#pragma mark - Overrides
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// FLEXLiveObjectsTableViewController.h
|
||||
// FLEXLiveObjectsController.h
|
||||
// Flipboard
|
||||
//
|
||||
// Created by Ryan Olson on 5/28/14.
|
||||
@@ -9,6 +9,6 @@
|
||||
#import "FLEXTableViewController.h"
|
||||
#import "FLEXGlobalsEntry.h"
|
||||
|
||||
@interface FLEXLiveObjectsTableViewController : FLEXTableViewController <FLEXGlobalsEntry>
|
||||
@interface FLEXLiveObjectsController : FLEXTableViewController <FLEXGlobalsEntry>
|
||||
|
||||
@end
|
||||
+7
-7
@@ -1,12 +1,12 @@
|
||||
//
|
||||
// FLEXLiveObjectsTableViewController.m
|
||||
// FLEXLiveObjectsController.m
|
||||
// Flipboard
|
||||
//
|
||||
// Created by Ryan Olson on 5/28/14.
|
||||
// Copyright (c) 2020 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXLiveObjectsTableViewController.h"
|
||||
#import "FLEXLiveObjectsController.h"
|
||||
#import "FLEXHeapEnumerator.h"
|
||||
#import "FLEXObjectListViewController.h"
|
||||
#import "FLEXUtility.h"
|
||||
@@ -18,7 +18,7 @@ static const NSInteger kFLEXLiveObjectsSortAlphabeticallyIndex = 0;
|
||||
static const NSInteger kFLEXLiveObjectsSortByCountIndex = 1;
|
||||
static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
|
||||
|
||||
@interface FLEXLiveObjectsTableViewController ()
|
||||
@interface FLEXLiveObjectsController ()
|
||||
|
||||
@property (nonatomic) NSDictionary<NSString *, NSNumber *> *instanceCountsForClassNames;
|
||||
@property (nonatomic) NSDictionary<NSString *, NSNumber *> *instanceSizesForClassNames;
|
||||
@@ -28,7 +28,7 @@ static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXLiveObjectsTableViewController
|
||||
@implementation FLEXLiveObjectsController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
@@ -139,7 +139,7 @@ static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
|
||||
}
|
||||
|
||||
+ (UIViewController *)globalsEntryViewController:(FLEXGlobalsRow)row {
|
||||
FLEXLiveObjectsTableViewController *liveObjectsViewController = [self new];
|
||||
FLEXLiveObjectsController *liveObjectsViewController = [self new];
|
||||
liveObjectsViewController.title = [self globalsEntryTitle:row];
|
||||
|
||||
return liveObjectsViewController;
|
||||
@@ -224,8 +224,8 @@ static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSString *className = self.filteredClassNames[indexPath.row];
|
||||
FLEXObjectListViewController *instancesViewController = [FLEXObjectListViewController instancesOfClassWithName:className];
|
||||
[self.navigationController pushViewController:instancesViewController animated:YES];
|
||||
UIViewController *instances = [FLEXObjectListViewController instancesOfClassWithName:className];
|
||||
[self.navigationController pushViewController:instances animated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -10,7 +10,9 @@
|
||||
|
||||
@interface FLEXObjectListViewController : FLEXFilteringTableViewController
|
||||
|
||||
+ (instancetype)instancesOfClassWithName:(NSString *)className;
|
||||
/// This will either return a list of the instances, or take you straight
|
||||
/// to the explorer itself if there is only one instance.
|
||||
+ (UIViewController *)instancesOfClassWithName:(NSString *)className;
|
||||
+ (instancetype)subclassesOfClassWithName:(NSString *)className;
|
||||
+ (instancetype)objectsWithReferencesToObject:(id)object;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#import "FLEXHeapEnumerator.h"
|
||||
#import "FLEXObjectRef.h"
|
||||
#import "NSString+FLEX.h"
|
||||
#import "NSObject+Reflection.h"
|
||||
#import "NSObject+FLEX_Reflection.h"
|
||||
#import "FLEXTableViewCell.h"
|
||||
#import <malloc/malloc.h>
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)instancesOfClassWithName:(NSString *)className {
|
||||
+ (UIViewController *)instancesOfClassWithName:(NSString *)className {
|
||||
const char *classNameCString = className.UTF8String;
|
||||
NSMutableArray *instances = [NSMutableArray new];
|
||||
[FLEXHeapEnumerator enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id object, __unsafe_unretained Class actualClass) {
|
||||
@@ -127,6 +127,12 @@
|
||||
}];
|
||||
|
||||
NSArray<FLEXObjectRef *> *references = [FLEXObjectRef referencingAll:instances];
|
||||
if (references.count == 1) {
|
||||
return [FLEXObjectExplorerFactory
|
||||
explorerViewControllerForObject:references.firstObject.object
|
||||
];
|
||||
}
|
||||
|
||||
FLEXObjectListViewController *controller = [[self alloc] initWithReferences:references];
|
||||
controller.title = [NSString stringWithFormat:@"%@ (%lu)", className, (unsigned long)instances.count];
|
||||
return controller;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#import "FLEXObjectRef.h"
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
|
||||
@interface FLEXObjectRef ()
|
||||
@property (nonatomic, readonly) BOOL wantsSummary;
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// FLEXFileBrowserTableViewController.h
|
||||
// FLEXFileBrowserController.h
|
||||
// Flipboard
|
||||
//
|
||||
// Created by Ryan Olson on 6/9/14.
|
||||
@@ -10,7 +10,7 @@
|
||||
#import "FLEXGlobalsEntry.h"
|
||||
#import "FLEXFileBrowserSearchOperation.h"
|
||||
|
||||
@interface FLEXFileBrowserTableViewController : FLEXTableViewController <FLEXGlobalsEntry>
|
||||
@interface FLEXFileBrowserController : FLEXTableViewController <FLEXGlobalsEntry>
|
||||
|
||||
+ (instancetype)path:(NSString *)path;
|
||||
- (id)initWithPath:(NSString *)path;
|
||||
+6
-6
@@ -1,12 +1,12 @@
|
||||
//
|
||||
// FLEXFileBrowserTableViewController.m
|
||||
// FLEXFileBrowserController.m
|
||||
// Flipboard
|
||||
//
|
||||
// Created by Ryan Olson on 6/9/14.
|
||||
//
|
||||
//
|
||||
|
||||
#import "FLEXFileBrowserTableViewController.h"
|
||||
#import "FLEXFileBrowserController.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXWebViewController.h"
|
||||
#import "FLEXImagePreviewViewController.h"
|
||||
@@ -18,7 +18,7 @@
|
||||
@interface FLEXFileBrowserTableViewCell : UITableViewCell
|
||||
@end
|
||||
|
||||
@interface FLEXFileBrowserTableViewController () <FLEXFileBrowserSearchOperationDelegate>
|
||||
@interface FLEXFileBrowserController () <FLEXFileBrowserSearchOperationDelegate>
|
||||
|
||||
@property (nonatomic, copy) NSString *path;
|
||||
@property (nonatomic, copy) NSArray<NSString *> *childPaths;
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXFileBrowserTableViewController
|
||||
@implementation FLEXFileBrowserController
|
||||
|
||||
+ (instancetype)path:(NSString *)path {
|
||||
return [[self alloc] initWithPath:path];
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
|
||||
//computing path size
|
||||
FLEXFileBrowserTableViewController *__weak weakSelf = self;
|
||||
FLEXFileBrowserController *__weak weakSelf = self;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSFileManager *fileManager = NSFileManager.defaultManager;
|
||||
NSDictionary<NSString *, id> *attributes = [fileManager attributesOfItemAtPath:path error:NULL];
|
||||
@@ -66,7 +66,7 @@
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
FLEXFileBrowserTableViewController *__strong strongSelf = weakSelf;
|
||||
FLEXFileBrowserController *__strong strongSelf = weakSelf;
|
||||
strongSelf.recursiveSize = @(totalSize);
|
||||
[strongSelf.tableView reloadData];
|
||||
});
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#import "FLEXGlobalsSection.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "UIFont+FLEX.h"
|
||||
|
||||
@interface FLEXGlobalsSection ()
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#import "FLEXObjcRuntimeViewController.h"
|
||||
#import "FLEXKeychainTableViewController.h"
|
||||
#import "FLEXKeychainViewController.h"
|
||||
#import "FLEXObjectExplorerViewController.h"
|
||||
#import "FLEXObjectExplorerFactory.h"
|
||||
#import "FLEXLiveObjectsTableViewController.h"
|
||||
#import "FLEXFileBrowserTableViewController.h"
|
||||
#import "FLEXCookiesTableViewController.h"
|
||||
#import "FLEXLiveObjectsController.h"
|
||||
#import "FLEXFileBrowserController.h"
|
||||
#import "FLEXCookiesViewController.h"
|
||||
#import "FLEXGlobalsEntry.h"
|
||||
#import "FLEXManager+Private.h"
|
||||
#import "FLEXSystemLogViewController.h"
|
||||
@@ -56,18 +56,18 @@
|
||||
+ (FLEXGlobalsEntry *)globalsEntryForRow:(FLEXGlobalsRow)row {
|
||||
switch (row) {
|
||||
case FLEXGlobalsRowAppKeychainItems:
|
||||
return [FLEXKeychainTableViewController flex_concreteGlobalsEntry:row];
|
||||
return [FLEXKeychainViewController flex_concreteGlobalsEntry:row];
|
||||
case FLEXGlobalsRowAddressInspector:
|
||||
return [FLEXAddressExplorerCoordinator flex_concreteGlobalsEntry:row];
|
||||
case FLEXGlobalsRowBrowseRuntime:
|
||||
return [FLEXObjcRuntimeViewController flex_concreteGlobalsEntry:row];
|
||||
case FLEXGlobalsRowLiveObjects:
|
||||
return [FLEXLiveObjectsTableViewController flex_concreteGlobalsEntry:row];
|
||||
return [FLEXLiveObjectsController flex_concreteGlobalsEntry:row];
|
||||
case FLEXGlobalsRowCookies:
|
||||
return [FLEXCookiesTableViewController flex_concreteGlobalsEntry:row];
|
||||
return [FLEXCookiesViewController flex_concreteGlobalsEntry:row];
|
||||
case FLEXGlobalsRowBrowseBundle:
|
||||
case FLEXGlobalsRowBrowseContainer:
|
||||
return [FLEXFileBrowserTableViewController flex_concreteGlobalsEntry:row];
|
||||
return [FLEXFileBrowserController flex_concreteGlobalsEntry:row];
|
||||
case FLEXGlobalsRowSystemLog:
|
||||
return [FLEXSystemLogViewController flex_concreteGlobalsEntry:row];
|
||||
case FLEXGlobalsRowNetworkHistory:
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// FLEXKeychainTableViewController.h
|
||||
// FLEXKeychainViewController.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by ray on 2019/8/17.
|
||||
@@ -9,6 +9,6 @@
|
||||
#import "FLEXGlobalsEntry.h"
|
||||
#import "FLEXFilteringTableViewController.h"
|
||||
|
||||
@interface FLEXKeychainTableViewController : FLEXFilteringTableViewController <FLEXGlobalsEntry>
|
||||
@interface FLEXKeychainViewController : FLEXFilteringTableViewController <FLEXGlobalsEntry>
|
||||
|
||||
@end
|
||||
+10
-13
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// FLEXKeychainTableViewController.m
|
||||
// FLEXKeychainViewController.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by ray on 2019/8/17.
|
||||
@@ -8,17 +8,18 @@
|
||||
|
||||
#import "FLEXKeychain.h"
|
||||
#import "FLEXKeychainQuery.h"
|
||||
#import "FLEXKeychainTableViewController.h"
|
||||
#import "FLEXKeychainViewController.h"
|
||||
#import "FLEXTableViewCell.h"
|
||||
#import "FLEXMutableListSection.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "UIPasteboard+FLEX.h"
|
||||
#import "UIBarButtonItem+FLEX.h"
|
||||
|
||||
@interface FLEXKeychainTableViewController ()
|
||||
@interface FLEXKeychainViewController ()
|
||||
@property (nonatomic, readonly) FLEXMutableListSection<NSDictionary *> *section;
|
||||
@end
|
||||
|
||||
@implementation FLEXKeychainTableViewController
|
||||
@implementation FLEXKeychainViewController
|
||||
|
||||
- (id)init {
|
||||
return [self initWithStyle:UITableViewStyleGrouped];
|
||||
@@ -30,12 +31,8 @@
|
||||
[super viewDidLoad];
|
||||
|
||||
self.navigationItem.rightBarButtonItems = @[
|
||||
[[UIBarButtonItem alloc]
|
||||
initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(trashPressed)
|
||||
],
|
||||
[[UIBarButtonItem alloc]
|
||||
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addPressed)
|
||||
],
|
||||
[UIBarButtonItem systemItem:UIBarButtonSystemItemTrash target:self action:@selector(trashPressed:)],
|
||||
[UIBarButtonItem systemItem:UIBarButtonSystemItemAdd target:self action:@selector(addPressed)],
|
||||
];
|
||||
|
||||
[self reloadData];
|
||||
@@ -127,7 +124,7 @@
|
||||
|
||||
#pragma mark Buttons
|
||||
|
||||
- (void)trashPressed {
|
||||
- (void)trashPressed:(UIBarButtonItem *)sender {
|
||||
[FLEXAlert makeSheet:^(FLEXAlert *make) {
|
||||
make.title(@"Clear Keychain");
|
||||
make.message(@"This will remove all keychain items for this app.\n");
|
||||
@@ -140,7 +137,7 @@
|
||||
[self reloadData];
|
||||
});
|
||||
make.button(@"Cancel").cancelStyle();
|
||||
} showFrom:self];
|
||||
} showFrom:self source:sender];
|
||||
}
|
||||
|
||||
- (void)addPressed {
|
||||
@@ -170,7 +167,7 @@
|
||||
}
|
||||
|
||||
+ (UIViewController *)globalsEntryViewController:(FLEXGlobalsRow)row {
|
||||
FLEXKeychainTableViewController *viewController = [self new];
|
||||
FLEXKeychainViewController *viewController = [self new];
|
||||
viewController.title = [self globalsEntryTitle:row];
|
||||
|
||||
return viewController;
|
||||
@@ -19,6 +19,17 @@
|
||||
/// been loaded since this method was first called.
|
||||
- (void)reloadLibrariesList;
|
||||
|
||||
/// You must call this method on the main thread
|
||||
/// before you attempt to call \c copySafeClassList.
|
||||
+ (void)initializeWebKitLegacy;
|
||||
|
||||
/// Do not call unless you absolutely need all classes. This will cause
|
||||
/// every class in the runtime to initialize itself, which is not common.
|
||||
/// Before you call this method, call \c initializeWebKitLegacy on the main thread.
|
||||
- (NSArray<Class> *)copySafeClassList;
|
||||
|
||||
- (NSArray<Protocol *> *)copyProtocolList;
|
||||
|
||||
/// An array of strings representing the currently loaded libraries.
|
||||
@property (nonatomic, readonly) NSArray<NSString *> *imageDisplayNames;
|
||||
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
//
|
||||
|
||||
#import "FLEXRuntimeClient.h"
|
||||
#import "NSObject+Reflection.h"
|
||||
#import "NSObject+FLEX_Reflection.h"
|
||||
#import "FLEXMethod.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "FLEXRuntimeSafety.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define Equals(a, b) ([a compare:b options:NSCaseInsensitiveSearch] == NSOrderedSame)
|
||||
#define Contains(a, b) ([a rangeOfString:b options:NSCaseInsensitiveSearch].location != NSNotFound)
|
||||
@@ -187,6 +188,38 @@ static inline NSString * TBWildcardMap(NSString *token, NSString *candidate, TBW
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
+ (void)initializeWebKitLegacy {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
void *handle = dlopen(
|
||||
"/System/Library/PrivateFrameworks/WebKitLegacy.framework/WebKitLegacy",
|
||||
RTLD_LAZY
|
||||
);
|
||||
void (*WebKitInitialize)() = dlsym(handle, "WebKitInitialize");
|
||||
if (WebKitInitialize) {
|
||||
NSAssert(NSThread.isMainThread,
|
||||
@"WebKitInitialize can only be called on the main thread"
|
||||
);
|
||||
WebKitInitialize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (NSArray<Class> *)copySafeClassList {
|
||||
unsigned int count = 0;
|
||||
Class *classes = objc_copyClassList(&count);
|
||||
return [NSArray flex_forEachUpTo:count map:^id(NSUInteger i) {
|
||||
Class cls = classes[i];
|
||||
return FLEXClassIsSafe(cls) ? cls : nil;
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSArray<Protocol *> *)copyProtocolList {
|
||||
unsigned int count = 0;
|
||||
Protocol *__unsafe_unretained *protocols = objc_copyProtocolList(&count);
|
||||
return [NSArray arrayWithObjects:protocols count:count];
|
||||
}
|
||||
|
||||
- (NSMutableArray<NSString *> *)bundleNamesForToken:(FLEXSearchToken *)token {
|
||||
if (self.imagePaths.count) {
|
||||
TBWildcardOptions options = token.options;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#import "FLEXRuntimeKeyPath.h"
|
||||
|
||||
/// Wraps FLEXRuntimeClient and provides caching mechanisms
|
||||
/// Wraps FLEXRuntimeClient and provides extra caching mechanisms
|
||||
@interface FLEXRuntimeController : NSObject
|
||||
|
||||
/// @return An array of strings if the key path only evaluates
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
+ (NSString *)imagePathWithShortName:(NSString *)suffix;
|
||||
|
||||
/// Gives back short names. For example, "Foundation.framework"
|
||||
+ (NSArray<NSString*> *)allBundleNames;
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// FLEXRuntimeExporter.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner Bennett on 3/26/20.
|
||||
// Copyright (c) 2020 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// A class for exporting all runtime metadata to an SQLite database.
|
||||
//API_AVAILABLE(ios(10.0))
|
||||
@interface FLEXRuntimeExporter : NSObject
|
||||
|
||||
+ (void)createRuntimeDatabaseAtPath:(NSString *)path
|
||||
progressHandler:(void(^)(NSString *status))progress
|
||||
completion:(void(^)(NSString *_Nullable error))completion;
|
||||
|
||||
+ (void)createRuntimeDatabaseAtPath:(NSString *)path
|
||||
forImages:(nullable NSArray<NSString *> *)images
|
||||
progressHandler:(void(^)(NSString *status))progress
|
||||
completion:(void(^)(NSString *_Nullable error))completion;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,875 @@
|
||||
//
|
||||
// FLEXRuntimeExporter.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner Bennett on 3/26/20.
|
||||
// Copyright (c) 2020 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXRuntimeExporter.h"
|
||||
#import "FLEXSQLiteDatabaseManager.h"
|
||||
#import "NSObject+FLEX_Reflection.h"
|
||||
#import "FLEXRuntimeController.h"
|
||||
#import "FLEXRuntimeClient.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "FLEXTypeEncodingParser.h"
|
||||
#import <sqlite3.h>
|
||||
|
||||
#import "FLEXProtocol.h"
|
||||
#import "FLEXProperty.h"
|
||||
#import "FLEXIvar.h"
|
||||
#import "FLEXMethodBase.h"
|
||||
#import "FLEXMethod.h"
|
||||
#import "FLEXPropertyAttributes.h"
|
||||
|
||||
NSString * const kFREEnableForeignKeys = @"PRAGMA foreign_keys = ON;";
|
||||
|
||||
/// Loaded images
|
||||
NSString * const kFRECreateTableMachOCommand = @"CREATE TABLE MachO( "
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"shortName TEXT, "
|
||||
"imagePath TEXT, "
|
||||
"bundleID TEXT "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertImage = @"INSERT INTO MachO ( "
|
||||
"shortName, imagePath, bundleID "
|
||||
") VALUES ( "
|
||||
"$shortName, $imagePath, $bundleID "
|
||||
");";
|
||||
|
||||
/// Objc classes
|
||||
NSString * const kFRECreateTableClassCommand = @"CREATE TABLE Class( "
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"className TEXT, "
|
||||
"superclass INTEGER, "
|
||||
"instanceSize INTEGER, "
|
||||
"version INTEGER, "
|
||||
"image INTEGER, "
|
||||
|
||||
"FOREIGN KEY(superclass) REFERENCES Class(id), "
|
||||
"FOREIGN KEY(image) REFERENCES MachO(id) "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertClass = @"INSERT INTO Class ( "
|
||||
"className, instanceSize, version, image "
|
||||
") VALUES ( "
|
||||
"$className, $instanceSize, $version, $image "
|
||||
");";
|
||||
|
||||
NSString * const kFREUpdateClassSetSuper = @"UPDATE Class SET superclass = $super WHERE id = $id;";
|
||||
|
||||
/// Unique objc selectors
|
||||
NSString * const kFRECreateTableSelectorCommand = @"CREATE TABLE Selector( "
|
||||
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
|
||||
"name text NOT NULL UNIQUE "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertSelector = @"INSERT OR IGNORE INTO Selector (name) VALUES ($name);";
|
||||
|
||||
/// Unique objc type encodings
|
||||
NSString * const kFRECreateTableTypeEncodingCommand = @"CREATE TABLE TypeEncoding( "
|
||||
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
|
||||
"string text NOT NULL UNIQUE, "
|
||||
"size integer "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertTypeEncoding = @"INSERT OR IGNORE INTO TypeEncoding "
|
||||
"(string, size) VALUES ($type, $size);";
|
||||
|
||||
/// Unique objc type signatures
|
||||
NSString * const kFRECreateTableTypeSignatureCommand = @"CREATE TABLE TypeSignature( "
|
||||
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
|
||||
"string text NOT NULL UNIQUE "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertTypeSignature = @"INSERT OR IGNORE INTO TypeSignature "
|
||||
"(string) VALUES ($type);";
|
||||
|
||||
NSString * const kFRECreateTableMethodSignatureCommand = @"CREATE TABLE MethodSignature( "
|
||||
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
|
||||
"typeEncoding TEXT, "
|
||||
"argc INTEGER, "
|
||||
"returnType INTEGER, "
|
||||
"frameLength INTEGER, "
|
||||
|
||||
"FOREIGN KEY(returnType) REFERENCES TypeEncoding(id) "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertMethodSignature = @"INSERT INTO MethodSignature ( "
|
||||
"typeEncoding, argc, returnType, frameLength "
|
||||
") VALUES ( "
|
||||
"$typeEncoding, $argc, $returnType, $frameLength "
|
||||
");";
|
||||
|
||||
NSString * const kFRECreateTableMethodCommand = @"CREATE TABLE Method( "
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"sel INTEGER, "
|
||||
"class INTEGER, "
|
||||
"instance INTEGER, " // 0 if class method, 1 if instance method
|
||||
"signature INTEGER, "
|
||||
"image INTEGER, "
|
||||
|
||||
"FOREIGN KEY(sel) REFERENCES Selector(id), "
|
||||
"FOREIGN KEY(class) REFERENCES Class(id), "
|
||||
"FOREIGN KEY(signature) REFERENCES MethodSignature(id), "
|
||||
"FOREIGN KEY(image) REFERENCES MachO(id) "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertMethod = @"INSERT INTO Method ( "
|
||||
"sel, class, instance, signature, image "
|
||||
") VALUES ( "
|
||||
"$sel, $class, $instance, $signature, $image "
|
||||
");";
|
||||
|
||||
NSString * const kFRECreateTablePropertyCommand = @"CREATE TABLE Property( "
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"name TEXT, "
|
||||
"class INTEGER, "
|
||||
"instance INTEGER, " // 0 if class prop, 1 if instance prop
|
||||
"image INTEGER, "
|
||||
"attributes TEXT, "
|
||||
|
||||
"customGetter INTEGER, "
|
||||
"customSetter INTEGER, "
|
||||
|
||||
"type INTEGER, "
|
||||
"ivar TEXT, "
|
||||
"readonly INTEGER, "
|
||||
"copy INTEGER, "
|
||||
"retained INTEGER, "
|
||||
"nonatomic INTEGER, "
|
||||
"dynamic INTEGER, "
|
||||
"weak INTEGER, "
|
||||
"canGC INTEGER, "
|
||||
|
||||
"FOREIGN KEY(class) REFERENCES Class(id), "
|
||||
"FOREIGN KEY(customGetter) REFERENCES Selector(id), "
|
||||
"FOREIGN KEY(customSetter) REFERENCES Selector(id), "
|
||||
"FOREIGN KEY(image) REFERENCES MachO(id) "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertProperty = @"INSERT INTO Property ( "
|
||||
"name, class, instance, attributes, image, "
|
||||
"customGetter, customSetter, type, ivar, readonly, "
|
||||
"copy, retained, nonatomic, dynamic, weak, canGC "
|
||||
") VALUES ( "
|
||||
"$name, $class, $instance, $attributes, $image, "
|
||||
"$customGetter, $customSetter, $type, $ivar, $readonly, "
|
||||
"$copy, $retained, $nonatomic, $dynamic, $weak, $canGC "
|
||||
");";
|
||||
|
||||
NSString * const kFRECreateTableIvarCommand = @"CREATE TABLE Ivar( "
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"name TEXT, "
|
||||
"offset INTEGER, "
|
||||
"type INTEGER, "
|
||||
"class INTEGER, "
|
||||
"image INTEGER, "
|
||||
|
||||
"FOREIGN KEY(type) REFERENCES TypeEncoding(id), "
|
||||
"FOREIGN KEY(class) REFERENCES Class(id), "
|
||||
"FOREIGN KEY(image) REFERENCES MachO(id) "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertIvar = @"INSERT INTO Ivar ( "
|
||||
"name, offset, type, class, image "
|
||||
") VALUES ( "
|
||||
"$name, $offset, $type, $class, $image "
|
||||
");";
|
||||
|
||||
NSString * const kFRECreateTableProtocolCommand = @"CREATE TABLE Protocol( "
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"name TEXT, "
|
||||
"image INTEGER, "
|
||||
|
||||
"FOREIGN KEY(image) REFERENCES MachO(id) "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertProtocol = @"INSERT INTO Protocol "
|
||||
"(name, image) VALUES ($name, $image);";
|
||||
|
||||
NSString * const kFRECreateTableProtocolPropertyCommand = @"CREATE TABLE ProtocolMember( "
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"protocol INTEGER, "
|
||||
"required INTEGER, "
|
||||
"instance INTEGER, " // 0 if class member, 1 if instance member
|
||||
|
||||
// Only of the two below is used
|
||||
"property TEXT, "
|
||||
"method TEXT, "
|
||||
|
||||
"image INTEGER, "
|
||||
|
||||
"FOREIGN KEY(protocol) REFERENCES Protocol(id), "
|
||||
"FOREIGN KEY(image) REFERENCES MachO(id) "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertProtocolMember = @"INSERT INTO ProtocolMember ( "
|
||||
"protocol, required, instance, property, method, image "
|
||||
") VALUES ( "
|
||||
"$protocol, $required, $instance, $property, $method, $image "
|
||||
");";
|
||||
|
||||
/// For protocols conforming to other protocols
|
||||
NSString * const kFRECreateTableProtocolConformanceCommand = @"CREATE TABLE ProtocolConformance( "
|
||||
"protocol INTEGER, "
|
||||
"conformance INTEGER, "
|
||||
|
||||
"FOREIGN KEY(protocol) REFERENCES Protocol(id), "
|
||||
"FOREIGN KEY(conformance) REFERENCES Protocol(id) "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertProtocolConformance = @"INSERT INTO ProtocolConformance "
|
||||
"(protocol, conformance) VALUES ($protocol, $conformance);";
|
||||
|
||||
/// For classes conforming to protocols
|
||||
NSString * const kFRECreateTableClassConformanceCommand = @"CREATE TABLE ClassConformance( "
|
||||
"class INTEGER, "
|
||||
"conformance INTEGER, "
|
||||
|
||||
"FOREIGN KEY(class) REFERENCES Class(id), "
|
||||
"FOREIGN KEY(conformance) REFERENCES Protocol(id) "
|
||||
");";
|
||||
|
||||
NSString * const kFREInsertClassConformance = @"INSERT INTO ClassConformance "
|
||||
"(class, conformance) VALUES ($class, $conformance);";
|
||||
|
||||
@interface FLEXRuntimeExporter ()
|
||||
@property (nonatomic, readonly) FLEXSQLiteDatabaseManager *db;
|
||||
@property (nonatomic, copy) NSArray<NSString *> *loadedShortBundleNames;
|
||||
@property (nonatomic, copy) NSArray<NSString *> *loadedBundlePaths;
|
||||
@property (nonatomic, copy) NSArray<FLEXProtocol *> *protocols;
|
||||
@property (nonatomic, copy) NSArray<Class> *classes;
|
||||
|
||||
@property (nonatomic) NSMutableDictionary<NSString *, NSNumber *> *bundlePathsToIDs;
|
||||
@property (nonatomic) NSMutableDictionary<NSString *, NSNumber *> *protocolsToIDs;
|
||||
@property (nonatomic) NSMutableDictionary<Class, NSNumber *> *classesToIDs;
|
||||
@property (nonatomic) NSMutableDictionary<NSString *, NSNumber *> *typeEncodingsToIDs;
|
||||
@property (nonatomic) NSMutableDictionary<NSString *, NSNumber *> *methodSignaturesToIDs;
|
||||
@property (nonatomic) NSMutableDictionary<NSString *, NSNumber *> *selectorsToIDs;
|
||||
@end
|
||||
|
||||
@implementation FLEXRuntimeExporter
|
||||
|
||||
+ (NSString *)tempFilename {
|
||||
NSString *temp = NSTemporaryDirectory();
|
||||
NSString *uuid = [NSUUID.UUID.UUIDString substringToIndex:8];
|
||||
NSString *filename = [NSString stringWithFormat:@"FLEXRuntimeDatabase-%@.db", uuid];
|
||||
return [temp stringByAppendingPathComponent:filename];
|
||||
}
|
||||
|
||||
+ (void)createRuntimeDatabaseAtPath:(NSString *)path
|
||||
progressHandler:(void(^)(NSString *status))progress
|
||||
completion:(void (^)(NSString *))completion {
|
||||
[self createRuntimeDatabaseAtPath:path forImages:nil progressHandler:progress completion:completion];
|
||||
}
|
||||
|
||||
+ (void)createRuntimeDatabaseAtPath:(NSString *)path
|
||||
forImages:(NSArray<NSString *> *)images
|
||||
progressHandler:(void(^)(NSString *status))progress
|
||||
completion:(void(^)(NSString *_Nullable error))completion {
|
||||
__typeof(completion) callback = ^(NSString *error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(error);
|
||||
});
|
||||
};
|
||||
|
||||
// This must be called on the main thread first
|
||||
if (NSThread.isMainThread) {
|
||||
[FLEXRuntimeClient initializeWebKitLegacy];
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
[FLEXRuntimeClient initializeWebKitLegacy];
|
||||
});
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
NSError *error = nil;
|
||||
NSString *errorMessage = nil;
|
||||
|
||||
// Get unused temp filename, remove existing database if any
|
||||
NSString *tempPath = [self tempFilename];
|
||||
if ([NSFileManager.defaultManager fileExistsAtPath:tempPath]) {
|
||||
[NSFileManager.defaultManager removeItemAtPath:tempPath error:&error];
|
||||
if (error) {
|
||||
callback(error.localizedDescription);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to create and populate the database, abort if we fail
|
||||
FLEXRuntimeExporter *exporter = [self new];
|
||||
exporter.loadedBundlePaths = images;
|
||||
if (![exporter createAndPopulateDatabaseAtPath:tempPath
|
||||
progressHandler:progress
|
||||
error:&errorMessage]) {
|
||||
// Remove temp database if it was not moved
|
||||
if ([NSFileManager.defaultManager fileExistsAtPath:tempPath]) {
|
||||
[NSFileManager.defaultManager removeItemAtPath:tempPath error:nil];
|
||||
}
|
||||
|
||||
callback(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove old database at given path
|
||||
if ([NSFileManager.defaultManager fileExistsAtPath:path]) {
|
||||
[NSFileManager.defaultManager removeItemAtPath:path error:&error];
|
||||
if (error) {
|
||||
callback(error.localizedDescription);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Move new database to desired path
|
||||
[NSFileManager.defaultManager moveItemAtPath:tempPath toPath:path error:&error];
|
||||
if (error) {
|
||||
callback(error.localizedDescription);
|
||||
}
|
||||
|
||||
// Remove temp database if it was not moved
|
||||
if ([NSFileManager.defaultManager fileExistsAtPath:tempPath]) {
|
||||
[NSFileManager.defaultManager removeItemAtPath:tempPath error:nil];
|
||||
}
|
||||
|
||||
callback(nil);
|
||||
});
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_bundlePathsToIDs = [NSMutableDictionary new];
|
||||
_protocolsToIDs = [NSMutableDictionary new];
|
||||
_classesToIDs = [NSMutableDictionary new];
|
||||
_typeEncodingsToIDs = [NSMutableDictionary new];
|
||||
_methodSignaturesToIDs = [NSMutableDictionary new];
|
||||
_selectorsToIDs = [NSMutableDictionary new];
|
||||
|
||||
_bundlePathsToIDs[NSNull.null] = (id)NSNull.null;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)createAndPopulateDatabaseAtPath:(NSString *)path
|
||||
progressHandler:(void(^)(NSString *status))step
|
||||
error:(NSString **)error {
|
||||
_db = [FLEXSQLiteDatabaseManager managerForDatabase:path];
|
||||
|
||||
[self loadMetadata:step];
|
||||
|
||||
if ([self createTables] && [self addImages:step] && [self addProtocols:step] &&
|
||||
[self addClasses:step] && [self setSuperclasses:step] &&
|
||||
[self addProtocolConformances:step] && [self addClassConformances:step] &&
|
||||
[self addIvars:step] && [self addMethods:step] && [self addProperties:step]) {
|
||||
_db = nil; // Close the database
|
||||
return YES;
|
||||
}
|
||||
|
||||
*error = self.db.lastResult.message;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)loadMetadata:(void(^)(NSString *status))progress {
|
||||
progress(@"Loading metadata…");
|
||||
|
||||
FLEXRuntimeClient *runtime = FLEXRuntimeClient.runtime;
|
||||
|
||||
// Only load metadata for the existing paths if any
|
||||
if (self.loadedBundlePaths) {
|
||||
// Images
|
||||
self.loadedShortBundleNames = [self.loadedBundlePaths flex_mapped:^id(NSString *path, NSUInteger idx) {
|
||||
return [runtime shortNameForImageName:path];
|
||||
}];
|
||||
|
||||
// Classes
|
||||
self.classes = [[runtime classesForToken:FLEXSearchToken.any
|
||||
inBundles:self.loadedBundlePaths.mutableCopy
|
||||
] flex_mapped:^id(NSString *cls, NSUInteger idx) {
|
||||
return NSClassFromString(cls);
|
||||
}];
|
||||
} else {
|
||||
// Images
|
||||
self.loadedShortBundleNames = runtime.imageDisplayNames;
|
||||
self.loadedBundlePaths = [self.loadedShortBundleNames flex_mapped:^id(NSString *name, NSUInteger idx) {
|
||||
return [runtime imageNameForShortName:name];
|
||||
}];
|
||||
|
||||
// Classes
|
||||
self.classes = [runtime copySafeClassList];
|
||||
}
|
||||
|
||||
// ...except protocols, because there's not a lot of them
|
||||
// and there's no way load the protocols for a given image
|
||||
self.protocols = [[runtime copyProtocolList] flex_mapped:^id(Protocol *proto, NSUInteger idx) {
|
||||
return [FLEXProtocol protocol:proto];
|
||||
}];
|
||||
}
|
||||
|
||||
- (BOOL)createTables {
|
||||
NSArray<NSString *> *commands = @[
|
||||
kFREEnableForeignKeys,
|
||||
kFRECreateTableMachOCommand,
|
||||
kFRECreateTableClassCommand,
|
||||
kFRECreateTableSelectorCommand,
|
||||
kFRECreateTableTypeEncodingCommand,
|
||||
kFRECreateTableTypeSignatureCommand,
|
||||
kFRECreateTableMethodSignatureCommand,
|
||||
kFRECreateTableMethodCommand,
|
||||
kFRECreateTablePropertyCommand,
|
||||
kFRECreateTableIvarCommand,
|
||||
kFRECreateTableProtocolCommand,
|
||||
kFRECreateTableProtocolPropertyCommand,
|
||||
kFRECreateTableProtocolConformanceCommand,
|
||||
kFRECreateTableClassConformanceCommand
|
||||
];
|
||||
|
||||
for (NSString *command in commands) {
|
||||
if (![self.db executeStatement:command]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)addImages:(void(^)(NSString *status))progress {
|
||||
progress(@"Adding loaded images…");
|
||||
|
||||
FLEXSQLiteDatabaseManager *database = self.db;
|
||||
NSArray *shortNames = self.loadedShortBundleNames;
|
||||
NSArray *fullPaths = self.loadedBundlePaths;
|
||||
NSParameterAssert(shortNames.count == fullPaths.count);
|
||||
|
||||
NSInteger count = shortNames.count;
|
||||
for (NSInteger i = 0; i < count; i++) {
|
||||
// Grab bundle ID
|
||||
NSString *bundleID = [NSBundle
|
||||
bundleWithPath:fullPaths[i]
|
||||
].bundleIdentifier;
|
||||
|
||||
[database executeStatement:kFREInsertImage arguments:@{
|
||||
@"$shortName": shortNames[i],
|
||||
@"$imagePath": fullPaths[i],
|
||||
@"$bundleID": bundleID ?: NSNull.null
|
||||
}];
|
||||
|
||||
if (database.lastResult.isError) {
|
||||
return NO;
|
||||
} else {
|
||||
self.bundlePathsToIDs[fullPaths[i]] = @(database.lastRowID);
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
NS_INLINE BOOL FREInsertProtocolMember(FLEXSQLiteDatabaseManager *db,
|
||||
id proto, id required, id instance,
|
||||
id prop, id methSel, id image) {
|
||||
return ![db executeStatement:kFREInsertProtocolMember arguments:@{
|
||||
@"$protocol": proto,
|
||||
@"$required": required,
|
||||
@"$instance": instance ?: NSNull.null,
|
||||
@"$property": prop ?: NSNull.null,
|
||||
@"$method": methSel ?: NSNull.null,
|
||||
@"$image": image
|
||||
}].isError;
|
||||
}
|
||||
|
||||
- (BOOL)addProtocols:(void(^)(NSString *status))progress {
|
||||
progress([NSString stringWithFormat:@"Adding %@ protocols…", @(self.protocols.count)]);
|
||||
|
||||
FLEXSQLiteDatabaseManager *database = self.db;
|
||||
NSDictionary *imageIDs = self.bundlePathsToIDs;
|
||||
|
||||
for (FLEXProtocol *proto in self.protocols) {
|
||||
id imagePath = proto.imagePath ?: NSNull.null;
|
||||
NSNumber *image = imageIDs[imagePath] ?: NSNull.null;
|
||||
NSNumber *pid = nil;
|
||||
|
||||
// Insert protocol
|
||||
BOOL failed = [database executeStatement:kFREInsertProtocol arguments:@{
|
||||
@"$name": proto.name, @"$image": image
|
||||
}].isError;
|
||||
|
||||
// Cache rowid
|
||||
if (failed) {
|
||||
return NO;
|
||||
} else {
|
||||
self.protocolsToIDs[proto.name] = pid = @(database.lastRowID);
|
||||
}
|
||||
|
||||
// Insert its members //
|
||||
|
||||
// Required methods
|
||||
for (FLEXMethodDescription *method in proto.requiredMethods) {
|
||||
NSString *selector = NSStringFromSelector(method.selector);
|
||||
if (!FREInsertProtocolMember(database, pid, @YES, method.instance, nil, selector, image)) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
// Optional methods
|
||||
for (FLEXMethodDescription *method in proto.optionalMethods) {
|
||||
NSString *selector = NSStringFromSelector(method.selector);
|
||||
if (!FREInsertProtocolMember(database, pid, @NO, method.instance, nil, selector, image)) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
if (@available(iOS 10, *)) {
|
||||
// Required properties
|
||||
for (FLEXProperty *property in proto.requiredProperties) {
|
||||
BOOL success = FREInsertProtocolMember(
|
||||
database, pid, @YES, @(property.isClassProperty), property.name, NSNull.null, image
|
||||
);
|
||||
|
||||
if (!success) return NO;
|
||||
}
|
||||
// Optional properties
|
||||
for (FLEXProperty *property in proto.optionalProperties) {
|
||||
BOOL success = FREInsertProtocolMember(
|
||||
database, pid, @NO, @(property.isClassProperty), property.name, NSNull.null, image
|
||||
);
|
||||
|
||||
if (!success) return NO;
|
||||
}
|
||||
} else {
|
||||
// Just... properties.
|
||||
for (FLEXProperty *property in proto.properties) {
|
||||
BOOL success = FREInsertProtocolMember(
|
||||
database, pid, nil, @(property.isClassProperty), property.name, NSNull.null, image
|
||||
);
|
||||
|
||||
if (!success) return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)addProtocolConformances:(void(^)(NSString *status))progress {
|
||||
progress(@"Adding protocol-to-protocol conformances…");
|
||||
|
||||
FLEXSQLiteDatabaseManager *database = self.db;
|
||||
NSDictionary *protocolIDs = self.protocolsToIDs;
|
||||
|
||||
for (FLEXProtocol *proto in self.protocols) {
|
||||
id protoID = protocolIDs[proto.name];
|
||||
|
||||
for (FLEXProtocol *conform in proto.protocols) {
|
||||
BOOL failed = [database executeStatement:kFREInsertProtocolConformance arguments:@{
|
||||
@"$protocol": protoID,
|
||||
@"$conformance": protocolIDs[conform.name]
|
||||
}].isError;
|
||||
|
||||
if (failed) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)addClasses:(void(^)(NSString *status))progress {
|
||||
progress([NSString stringWithFormat:@"Adding %@ classes…", @(self.classes.count)]);
|
||||
|
||||
FLEXSQLiteDatabaseManager *database = self.db;
|
||||
NSDictionary *imageIDs = self.bundlePathsToIDs;
|
||||
|
||||
for (Class cls in self.classes) {
|
||||
const char *imageName = class_getImageName(cls);
|
||||
id image = imageName ? imageIDs[@(imageName)] : NSNull.null;
|
||||
image = image ?: NSNull.null;
|
||||
|
||||
BOOL failed = [database executeStatement:kFREInsertClass arguments:@{
|
||||
@"$className": NSStringFromClass(cls),
|
||||
@"$instanceSize": @(class_getInstanceSize(cls)),
|
||||
@"$version": @(class_getVersion(cls)),
|
||||
@"$image": image
|
||||
}].isError;
|
||||
|
||||
if (failed) {
|
||||
return NO;
|
||||
} else {
|
||||
self.classesToIDs[(id)cls] = @(database.lastRowID);
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)setSuperclasses:(void(^)(NSString *status))progress {
|
||||
progress(@"Setting superclasses…");
|
||||
|
||||
FLEXSQLiteDatabaseManager *database = self.db;
|
||||
|
||||
for (Class cls in self.classes) {
|
||||
// Grab superclass ID
|
||||
Class superclass = class_getSuperclass(cls);
|
||||
NSNumber *superclassID = _classesToIDs[class_getSuperclass(cls)];
|
||||
|
||||
// ... or add the superclass and cache its ID if the
|
||||
// superclass does not reside in the target image(s)
|
||||
if (!superclassID) {
|
||||
NSDictionary *args = @{ @"$className": NSStringFromClass(superclass) };
|
||||
BOOL failed = [database executeStatement:kFREInsertClass arguments:args].isError;
|
||||
if (failed) { return NO; }
|
||||
|
||||
_classesToIDs[(id)superclass] = superclassID = @(database.lastRowID);
|
||||
}
|
||||
|
||||
if (superclass) {
|
||||
BOOL failed = [database executeStatement:kFREUpdateClassSetSuper arguments:@{
|
||||
@"$super": superclassID, @"$id": _classesToIDs[cls]
|
||||
}].isError;
|
||||
|
||||
if (failed) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)addClassConformances:(void(^)(NSString *status))progress {
|
||||
progress(@"Adding class-to-protocol conformances…");
|
||||
|
||||
FLEXSQLiteDatabaseManager *database = self.db;
|
||||
NSDictionary *protocolIDs = self.protocolsToIDs;
|
||||
NSDictionary *classIDs = self.classesToIDs;
|
||||
|
||||
for (Class cls in self.classes) {
|
||||
id classID = classIDs[(id)cls];
|
||||
|
||||
for (FLEXProtocol *conform in FLEXGetConformedProtocols(cls)) {
|
||||
BOOL failed = [database executeStatement:kFREInsertClassConformance arguments:@{
|
||||
@"$class": classID,
|
||||
@"$conformance": protocolIDs[conform.name]
|
||||
}].isError;
|
||||
|
||||
if (failed) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)addIvars:(void(^)(NSString *status))progress {
|
||||
progress(@"Adding ivars…");
|
||||
|
||||
FLEXSQLiteDatabaseManager *database = self.db;
|
||||
NSDictionary *imageIDs = self.bundlePathsToIDs;
|
||||
|
||||
for (Class cls in self.classes) {
|
||||
for (FLEXIvar *ivar in FLEXGetAllIvars(cls)) {
|
||||
// Insert type first
|
||||
if (![self addTypeEncoding:ivar.typeEncoding size:ivar.size]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
id imagePath = ivar.imagePath ?: NSNull.null;
|
||||
NSNumber *image = imageIDs[imagePath] ?: NSNull.null;
|
||||
|
||||
BOOL failed = [database executeStatement:kFREInsertIvar arguments:@{
|
||||
@"$name": ivar.name,
|
||||
@"$offset": @(ivar.offset),
|
||||
@"$type": _typeEncodingsToIDs[ivar.typeEncoding],
|
||||
@"$class": _classesToIDs[cls],
|
||||
@"$image": image
|
||||
}].isError;
|
||||
|
||||
if (failed) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)addMethods:(void(^)(NSString *status))progress {
|
||||
progress(@"Adding methods…");
|
||||
|
||||
FLEXSQLiteDatabaseManager *database = self.db;
|
||||
NSDictionary *imageIDs = self.bundlePathsToIDs;
|
||||
|
||||
// Loop over all classes
|
||||
for (Class cls in self.classes) {
|
||||
NSNumber *classID = _classesToIDs[(id)cls];
|
||||
const char *imageName = class_getImageName(cls);
|
||||
id image = imageName ? imageIDs[@(imageName)] : NSNull.null;
|
||||
image = image ?: NSNull.null;
|
||||
|
||||
// Block used to process each message
|
||||
BOOL (^insert)(FLEXMethod *, NSNumber *) = ^BOOL(FLEXMethod *method, NSNumber *instance) {
|
||||
// Insert selector and signature first
|
||||
if (![self addSelector:method.selectorString]) {
|
||||
return NO;
|
||||
}
|
||||
if (![self addMethodSignature:method]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return ![database executeStatement:kFREInsertMethod arguments:@{
|
||||
@"$sel": self->_selectorsToIDs[method.selectorString],
|
||||
@"$class": classID,
|
||||
@"$instance": instance,
|
||||
@"$signature": self->_methodSignaturesToIDs[method.signatureString],
|
||||
@"$image": image
|
||||
}].isError;
|
||||
};
|
||||
|
||||
// Loop over all instance and class methods of that class //
|
||||
|
||||
for (FLEXMethod *method in FLEXGetAllMethods(cls, YES)) {
|
||||
if (!insert(method, @YES)) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
for (FLEXMethod *method in FLEXGetAllMethods(object_getClass(cls), NO)) {
|
||||
if (!insert(method, @NO)) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)addProperties:(void(^)(NSString *status))progress {
|
||||
progress(@"Adding properties…");
|
||||
|
||||
FLEXSQLiteDatabaseManager *database = self.db;
|
||||
NSDictionary *imageIDs = self.bundlePathsToIDs;
|
||||
|
||||
// Loop over all classes
|
||||
for (Class cls in self.classes) {
|
||||
NSNumber *classID = _classesToIDs[(id)cls];
|
||||
|
||||
// Block used to process each message
|
||||
BOOL (^insert)(FLEXProperty *, NSNumber *) = ^BOOL(FLEXProperty *property, NSNumber *instance) {
|
||||
FLEXPropertyAttributes *attrs = property.attributes;
|
||||
NSString *customGetter = attrs.customGetterString;
|
||||
NSString *customSetter = attrs.customSetterString;
|
||||
|
||||
// Insert selectors first
|
||||
if (customGetter) {
|
||||
if (![self addSelector:customGetter]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
if (customSetter) {
|
||||
if (![self addSelector:customSetter]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert type encoding first
|
||||
NSInteger size = [FLEXTypeEncodingParser
|
||||
sizeForTypeEncoding:attrs.typeEncoding alignment:nil
|
||||
];
|
||||
if (![self addTypeEncoding:attrs.typeEncoding size:size]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
id imagePath = property.imagePath ?: NSNull.null;
|
||||
id image = imageIDs[imagePath] ?: NSNull.null;
|
||||
return ![database executeStatement:kFREInsertProperty arguments:@{
|
||||
@"$name": property.name,
|
||||
@"$class": classID,
|
||||
@"$instance": instance,
|
||||
@"$image": image,
|
||||
@"$attributes": attrs.string,
|
||||
|
||||
@"$customGetter": self->_selectorsToIDs[customGetter] ?: NSNull.null,
|
||||
@"$customSetter": self->_selectorsToIDs[customSetter] ?: NSNull.null,
|
||||
|
||||
@"$type": self->_typeEncodingsToIDs[attrs.typeEncoding] ?: NSNull.null,
|
||||
@"$ivar": attrs.backingIvar ?: NSNull.null,
|
||||
@"$readonly": @(attrs.isReadOnly),
|
||||
@"$copy": @(attrs.isCopy),
|
||||
@"$retained": @(attrs.isRetained),
|
||||
@"$nonatomic": @(attrs.isNonatomic),
|
||||
@"$dynamic": @(attrs.isDynamic),
|
||||
@"$weak": @(attrs.isWeak),
|
||||
@"$canGC": @(attrs.isGarbageCollectable),
|
||||
}].isError;
|
||||
};
|
||||
|
||||
// Loop over all instance and class methods of that class //
|
||||
|
||||
for (FLEXProperty *property in FLEXGetAllProperties(cls)) {
|
||||
if (!insert(property, @YES)) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
for (FLEXProperty *property in FLEXGetAllProperties(object_getClass(cls))) {
|
||||
if (!insert(property, @NO)) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)addSelector:(NSString *)sel {
|
||||
return [self executeInsert:kFREInsertSelector args:@{
|
||||
@"$name": sel
|
||||
} key:sel cacheResult:_selectorsToIDs];
|
||||
}
|
||||
|
||||
- (BOOL)addTypeEncoding:(NSString *)type size:(NSInteger)size {
|
||||
return [self executeInsert:kFREInsertTypeEncoding args:@{
|
||||
@"$type": type, @"$size": @(size)
|
||||
} key:type cacheResult:_typeEncodingsToIDs];
|
||||
}
|
||||
|
||||
- (BOOL)addMethodSignature:(FLEXMethod *)method {
|
||||
NSString *signature = method.signatureString;
|
||||
NSString *returnType = @((char *)method.returnType);
|
||||
|
||||
// Insert return type first
|
||||
if (![self addTypeEncoding:returnType size:method.returnSize]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return [self executeInsert:kFREInsertMethodSignature args:@{
|
||||
@"$typeEncoding": signature,
|
||||
@"$returnType": _typeEncodingsToIDs[returnType],
|
||||
@"$argc": @(method.numberOfArguments),
|
||||
@"$frameLength": @(method.signature.frameLength)
|
||||
} key:signature cacheResult:_methodSignaturesToIDs];
|
||||
}
|
||||
|
||||
- (BOOL)executeInsert:(NSString *)statement
|
||||
args:(NSDictionary *)args
|
||||
key:(NSString *)cacheKey
|
||||
cacheResult:(NSMutableDictionary<NSString *, NSNumber *> *)rowids {
|
||||
// Check if already inserted
|
||||
if (rowids[cacheKey]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Insert
|
||||
FLEXSQLiteDatabaseManager *database = _db;
|
||||
[database executeStatement:statement arguments:args];
|
||||
|
||||
if (database.lastResult.isError) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Cache rowid
|
||||
rowids[cacheKey] = @(database.lastRowID);
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -10,9 +10,9 @@
|
||||
#import "FLEXRuntimeKeyPathTokenizer.h"
|
||||
#import "FLEXRuntimeController.h"
|
||||
#import "NSString+FLEX.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "UITextField+Range.h"
|
||||
#import "NSTimer+Blocks.h"
|
||||
#import "NSTimer+FLEX.h"
|
||||
#import "FLEXTableView.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXObjectExplorerFactory.h"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#import "FLEXRuntimeKeyPath.h"
|
||||
#include <dlfcn.h>
|
||||
#import "FLEXRuntimeClient.h"
|
||||
|
||||
@interface FLEXRuntimeKeyPath () {
|
||||
NSString *flex_description;
|
||||
@@ -49,29 +49,12 @@
|
||||
keyPath->flex_description = keyPathString;
|
||||
|
||||
if (bundle.isAny && cls.isAny && method.isAny) {
|
||||
[self initializeWebKitLegacy];
|
||||
[FLEXRuntimeClient initializeWebKitLegacy];
|
||||
}
|
||||
|
||||
return keyPath;
|
||||
}
|
||||
|
||||
+ (void)initializeWebKitLegacy {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
void *handle = dlopen(
|
||||
"/System/Library/PrivateFrameworks/WebKitLegacy.framework/WebKitLegacy",
|
||||
RTLD_LAZY
|
||||
);
|
||||
void (*WebKitInitialize)() = dlsym(handle, "WebKitInitialize");
|
||||
if (WebKitInitialize) {
|
||||
NSAssert(NSThread.isMainThread,
|
||||
@"WebKitInitialize can only be called on the main thread"
|
||||
);
|
||||
WebKitInitialize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return flex_description;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,11 @@ static BOOL my_os_log_shim_enabled(void *addr) {
|
||||
#pragma mark - Initialization
|
||||
|
||||
+ (void)load {
|
||||
// User must opt-into disabling os_log
|
||||
if (!NSUserDefaults.standardUserDefaults.flex_disableOSLog) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Thanks to @Ram4096 on GitHub for telling me that
|
||||
// os_log is conditionally enabled by the SDK version
|
||||
void *addr = __builtin_return_address(0);
|
||||
@@ -51,7 +56,7 @@ static BOOL my_os_log_shim_enabled(void *addr) {
|
||||
return;
|
||||
}
|
||||
|
||||
FLEXDidHookNSLog = rebind_symbols((struct rebinding[1]) {{
|
||||
FLEXDidHookNSLog = flex_rebind_symbols((struct rebinding[1]) {{
|
||||
"os_log_shim_enabled",
|
||||
(void *)my_os_log_shim_enabled,
|
||||
(void **)&orig_os_log_shim_enabled
|
||||
@@ -108,7 +113,7 @@ static BOOL my_os_log_shim_enabled(void *addr) {
|
||||
}
|
||||
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
self.title = @"Loading...";
|
||||
self.title = @"Waiting for Logs...";
|
||||
|
||||
// Toolbar buttons //
|
||||
|
||||
@@ -123,11 +128,7 @@ static BOOL my_os_log_shim_enabled(void *addr) {
|
||||
action:@selector(showLogSettings)
|
||||
];
|
||||
|
||||
if (FLEXOSLogAvailable() && !FLEXNSLogHookWorks) {
|
||||
[self addToolbarItems:@[scrollDown, settings]];
|
||||
} else {
|
||||
[self addToolbarItems:@[scrollDown]];
|
||||
}
|
||||
[self addToolbarItems:@[scrollDown, settings]];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
@@ -191,17 +192,35 @@ static BOOL my_os_log_shim_enabled(void *addr) {
|
||||
}
|
||||
|
||||
- (void)showLogSettings {
|
||||
FLEXOSLogController *logController = (FLEXOSLogController *)self.logController;
|
||||
BOOL persistent = NSUserDefaults.standardUserDefaults.flex_cacheOSLogMessages;
|
||||
NSString *toggle = persistent ? @"Disable" : @"Enable";
|
||||
NSString *title = [@"Persistent logging: " stringByAppendingString:persistent ? @"ON" : @"OFF"];
|
||||
NSString *body = @"In iOS 10 and up, ASL is gone. The OS Log API is much more limited. "
|
||||
"To get as close to the old behavior as possible, logs must be collected manually at launch and stored.\n\n"
|
||||
"Turn this feature on only when you need it.";
|
||||
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
|
||||
BOOL disableOSLog = defaults.flex_disableOSLog;
|
||||
BOOL persistent = defaults.flex_cacheOSLogMessages;
|
||||
|
||||
NSString *aslToggle = disableOSLog ? @"Enable os_log (default)" : @"Disable os_log";
|
||||
NSString *persistence = persistent ? @"Disable persistent logging" : @"Enable persistent logging";
|
||||
|
||||
NSString *title = @"System Log Settings";
|
||||
NSString *body = @"In iOS 10 and up, ASL has been replaced by os_log. "
|
||||
"The os_log API is much more limited. Below, you can opt-into the old behavior "
|
||||
"if you want cleaner, more reliable logs within FLEX, but this will break "
|
||||
"anything that expects os_log to be working, such as Console.app. "
|
||||
"This setting requires the app to restart to take effect. \n\n"
|
||||
|
||||
"To get as close to the old behavior as possible with os_log enabled, logs must "
|
||||
"be collected manually at launch and stored. This setting has no effect "
|
||||
"on iOS 9 and below, or if os_log is disabled. "
|
||||
"You should only enable persistent logging when you need it.";
|
||||
|
||||
FLEXOSLogController *logController = (FLEXOSLogController *)self.logController;
|
||||
|
||||
[FLEXAlert makeAlert:^(FLEXAlert *make) {
|
||||
make.title(title).message(body).button(toggle).handler(^(NSArray<NSString *> *strings) {
|
||||
NSUserDefaults.standardUserDefaults.flex_cacheOSLogMessages = !persistent;
|
||||
make.title(title).message(body);
|
||||
make.button(aslToggle).destructiveStyle().handler(^(NSArray<NSString *> *strings) {
|
||||
[defaults toggleBoolForKey:kFLEXDefaultsDisableOSLogForceASLKey];
|
||||
});
|
||||
|
||||
make.button(persistence).handler(^(NSArray<NSString *> *strings) {
|
||||
[defaults toggleBoolForKey:kFLEXDefaultsiOSPersistentOSLogKey];
|
||||
logController.persistent = !persistent;
|
||||
[logController.messages addObjectsFromArray:self.logMessages.list];
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#import "FLEXExplorerViewController.h"
|
||||
#import "FLEXNetworkMITMViewController.h"
|
||||
#import "FLEXKeyboardHelpViewController.h"
|
||||
#import "FLEXFileBrowserTableViewController.h"
|
||||
#import "FLEXFileBrowserController.h"
|
||||
#import "FLEXUtility.h"
|
||||
|
||||
@interface FLEXManager (ExtensibilityPrivate)
|
||||
@@ -156,7 +156,7 @@
|
||||
} description:@"End editing text\n\t\tDismiss top view controller"];
|
||||
|
||||
[self registerSimulatorShortcutWithKey:@"o" modifiers:UIKeyModifierCommand|UIKeyModifierShift action:^{
|
||||
[self toggleTopViewControllerOfClass:[FLEXFileBrowserTableViewController class]];
|
||||
[self toggleTopViewControllerOfClass:[FLEXFileBrowserController class]];
|
||||
} description:@"Toggle file browser menu"];
|
||||
}
|
||||
|
||||
|
||||
@@ -11,21 +11,25 @@
|
||||
#import "FLEXNetworkObserver.h"
|
||||
#import "FLEXNetworkRecorder.h"
|
||||
#import "FLEXObjectExplorerFactory.h"
|
||||
#import "NSUserDefaults+FLEX.h"
|
||||
|
||||
@implementation FLEXManager (Networking)
|
||||
|
||||
+ (void)load {
|
||||
// Register array/dictionary viewer for JSON responses
|
||||
[self.sharedManager setCustomViewerForContentType:@"application/json"
|
||||
viewControllerFutureBlock:^UIViewController *(NSData *data) {
|
||||
id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
||||
if (jsonObject) {
|
||||
return [FLEXObjectExplorerFactory explorerViewControllerForObject:jsonObject];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
];
|
||||
if (NSUserDefaults.standardUserDefaults.flex_registerDictionaryJSONViewerOnLaunch) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Register array/dictionary viewer for JSON responses
|
||||
[self.sharedManager setCustomViewerForContentType:@"application/json"
|
||||
viewControllerFutureBlock:^UIViewController *(NSData *data) {
|
||||
id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
||||
if (jsonObject) {
|
||||
return [FLEXObjectExplorerFactory explorerViewControllerForObject:jsonObject];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isNetworkDebuggingEnabled {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#import "FLEXExplorerViewController.h"
|
||||
#import "FLEXWindow.h"
|
||||
#import "FLEXObjectExplorerViewController.h"
|
||||
#import "FLEXFileBrowserTableViewController.h"
|
||||
#import "FLEXFileBrowserController.h"
|
||||
|
||||
@interface FLEXManager () <FLEXWindowEventDelegate, FLEXExplorerViewControllerDelegate>
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
#import "FLEXNetworkTransaction.h"
|
||||
#import "FLEXNetworkRecorder.h"
|
||||
#import "FLEXNetworkObserver.h"
|
||||
#import "FLEXNetworkTransactionTableViewCell.h"
|
||||
#import "FLEXNetworkTransactionDetailTableViewController.h"
|
||||
#import "FLEXNetworkTransactionCell.h"
|
||||
#import "FLEXNetworkTransactionDetailController.h"
|
||||
#import "FLEXNetworkSettingsController.h"
|
||||
#import "FLEXGlobalsViewController.h"
|
||||
#import "UIBarButtonItem+FLEX.h"
|
||||
@@ -61,11 +61,11 @@
|
||||
]];
|
||||
|
||||
[self.tableView
|
||||
registerClass:[FLEXNetworkTransactionTableViewCell class]
|
||||
registerClass:[FLEXNetworkTransactionCell class]
|
||||
forCellReuseIdentifier:kFLEXNetworkTransactionCellIdentifier
|
||||
];
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
self.tableView.rowHeight = FLEXNetworkTransactionTableViewCell.preferredCellHeight;
|
||||
self.tableView.rowHeight = FLEXNetworkTransactionCell.preferredCellHeight;
|
||||
|
||||
[self registerForNotifications];
|
||||
[self updateTransactions];
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
#pragma mark Button Actions
|
||||
|
||||
- (void)settingsButtonTapped:(id)sender {
|
||||
- (void)settingsButtonTapped:(UIBarButtonItem *)sender {
|
||||
UIViewController *settings = [FLEXNetworkSettingsController new];
|
||||
settings.navigationItem.rightBarButtonItem = FLEXBarButtonItemSystem(
|
||||
Done, self, @selector(settingsViewControllerDoneTapped:)
|
||||
@@ -121,7 +121,7 @@
|
||||
[self presentViewController:nav animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)trashButtonTapped:(id)sender {
|
||||
- (void)trashButtonTapped:(UIBarButtonItem *)sender {
|
||||
[FLEXAlert makeSheet:^(FLEXAlert *make) {
|
||||
make.title(@"Clear All Recorded Requests?");
|
||||
make.message(@"This cannot be undone.");
|
||||
@@ -130,7 +130,7 @@
|
||||
make.button(@"Clear All").destructiveStyle().handler(^(NSArray *strings) {
|
||||
[FLEXNetworkRecorder.defaultRecorder clearRecordedActivity];
|
||||
});
|
||||
} showFrom:self];
|
||||
} showFrom:self source:sender];
|
||||
}
|
||||
|
||||
- (void)settingsViewControllerDoneTapped:(id)sender {
|
||||
@@ -311,7 +311,7 @@
|
||||
FLEXNetworkTransaction *transaction = notification.userInfo[kFLEXNetworkRecorderUserInfoTransactionKey];
|
||||
|
||||
// Update both the main table view and search table view if needed.
|
||||
for (FLEXNetworkTransactionTableViewCell *cell in [self.tableView visibleCells]) {
|
||||
for (FLEXNetworkTransactionCell *cell in [self.tableView visibleCells]) {
|
||||
if ([cell.transaction isEqual:transaction]) {
|
||||
// Using -[UITableView reloadRowsAtIndexPaths:withRowAnimation:] is overkill here and kicks off a lot of
|
||||
// work that can make the table view somewhat unresponsive when lots of updates are streaming in.
|
||||
@@ -352,7 +352,7 @@
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FLEXNetworkTransactionTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kFLEXNetworkTransactionCellIdentifier forIndexPath:indexPath];
|
||||
FLEXNetworkTransactionCell *cell = [tableView dequeueReusableCellWithIdentifier:kFLEXNetworkTransactionCellIdentifier forIndexPath:indexPath];
|
||||
cell.transaction = [self transactionAtIndexPath:indexPath];
|
||||
|
||||
// Since we insert from the top, assign background colors bottom up to keep them consistent for each transaction.
|
||||
@@ -367,7 +367,7 @@
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FLEXNetworkTransactionDetailTableViewController *detailViewController = [FLEXNetworkTransactionDetailTableViewController new];
|
||||
FLEXNetworkTransactionDetailController *detailViewController = [FLEXNetworkTransactionDetailController new];
|
||||
detailViewController.transaction = [self transactionAtIndexPath:indexPath];
|
||||
[self.navigationController pushViewController:detailViewController animated:YES];
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXTableView.h"
|
||||
#import "FLEXColor.h"
|
||||
#import "NSUserDefaults+FLEX.h"
|
||||
|
||||
@interface FLEXNetworkSettingsController () <UIActionSheetDelegate>
|
||||
@property (nonatomic) float cacheLimitValue;
|
||||
@@ -18,6 +19,7 @@
|
||||
|
||||
@property (nonatomic, readonly) UISwitch *observerSwitch;
|
||||
@property (nonatomic, readonly) UISwitch *cacheMediaSwitch;
|
||||
@property (nonatomic, readonly) UISwitch *jsonViewerSwitch;
|
||||
@property (nonatomic, readonly) UISlider *cacheLimitSlider;
|
||||
@property (nonatomic) UILabel *cacheLimitLabel;
|
||||
|
||||
@@ -32,8 +34,11 @@
|
||||
[self disableToolbar];
|
||||
self.hostBlacklist = FLEXNetworkRecorder.defaultRecorder.hostBlacklist.mutableCopy;
|
||||
|
||||
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
|
||||
|
||||
_observerSwitch = [UISwitch new];
|
||||
_cacheMediaSwitch = [UISwitch new];
|
||||
_jsonViewerSwitch = [UISwitch new];
|
||||
_cacheLimitSlider = [UISlider new];
|
||||
|
||||
self.observerSwitch.on = FLEXNetworkObserver.enabled;
|
||||
@@ -48,6 +53,12 @@
|
||||
forControlEvents:UIControlEventValueChanged
|
||||
];
|
||||
|
||||
self.jsonViewerSwitch.on = defaults.flex_registerDictionaryJSONViewerOnLaunch;
|
||||
[self.jsonViewerSwitch addTarget:self
|
||||
action:@selector(jsonViewerSettingToggled:)
|
||||
forControlEvents:UIControlEventValueChanged
|
||||
];
|
||||
|
||||
[self.cacheLimitSlider addTarget:self
|
||||
action:@selector(cacheLimitAdjusted:)
|
||||
forControlEvents:UIControlEventValueChanged
|
||||
@@ -84,12 +95,16 @@
|
||||
FLEXNetworkRecorder.defaultRecorder.shouldCacheMediaResponses = sender.isOn;
|
||||
}
|
||||
|
||||
- (void)jsonViewerSettingToggled:(UISwitch *)sender {
|
||||
[NSUserDefaults.standardUserDefaults toggleBoolForKey:kFLEXDefaultsRegisterJSONExplorerKey];
|
||||
}
|
||||
|
||||
- (void)cacheLimitAdjusted:(UISlider *)sender {
|
||||
self.cacheLimitValue = sender.value;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Table View
|
||||
#pragma mark - Table View Data Source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return self.hostBlacklist.count ? 2 : 1;
|
||||
@@ -97,7 +112,7 @@
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
switch (section) {
|
||||
case 0: return 4;
|
||||
case 0: return 5;
|
||||
case 1: return self.hostBlacklist.count;
|
||||
default: return 0;
|
||||
}
|
||||
@@ -111,6 +126,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
|
||||
if (section == 0) {
|
||||
return @"By default, JSON is rendered in a webview. Turn on "
|
||||
"\"View JSON as a dictionary/array\" to convert JSON payloads "
|
||||
"to objects and view them in an object explorer. "
|
||||
"This setting requires a restart of the app.";
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *cell = [self.tableView
|
||||
dequeueReusableCellWithIdentifier:kFLEXDefaultCell forIndexPath:indexPath
|
||||
@@ -132,10 +158,14 @@
|
||||
cell.accessoryView = self.cacheMediaSwitch;
|
||||
break;
|
||||
case 2:
|
||||
cell.textLabel.text = @"View JSON as a dictionary/array";
|
||||
cell.accessoryView = self.jsonViewerSwitch;
|
||||
break;
|
||||
case 3:
|
||||
cell.textLabel.text = @"Reset Host Blacklist";
|
||||
cell.textLabel.textColor = tableView.tintColor;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
cell.textLabel.text = self.cacheLimitCellTitle;
|
||||
self.cacheLimitLabel = cell.textLabel;
|
||||
[self.cacheLimitSlider removeFromSuperview];
|
||||
@@ -179,6 +209,8 @@
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Table View Delegate
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)ip {
|
||||
// Can only select the "Reset Host Blacklist" row
|
||||
return ip.section == 0 && ip.row == 2;
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// FLEXNetworkTransactionTableViewCell.h
|
||||
// FLEXNetworkTransactionCell.h
|
||||
// Flipboard
|
||||
//
|
||||
// Created by Ryan Olson on 2/8/15.
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
extern NSString *const kFLEXNetworkTransactionCellIdentifier;
|
||||
extern NSString * const kFLEXNetworkTransactionCellIdentifier;
|
||||
|
||||
@class FLEXNetworkTransaction;
|
||||
|
||||
@interface FLEXNetworkTransactionTableViewCell : UITableViewCell
|
||||
@interface FLEXNetworkTransactionCell : UITableViewCell
|
||||
|
||||
@property (nonatomic) FLEXNetworkTransaction *transaction;
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// FLEXNetworkTransactionTableViewCell.m
|
||||
// FLEXNetworkTransactionCell.m
|
||||
// Flipboard
|
||||
//
|
||||
// Created by Ryan Olson on 2/8/15.
|
||||
@@ -7,14 +7,14 @@
|
||||
//
|
||||
|
||||
#import "FLEXColor.h"
|
||||
#import "FLEXNetworkTransactionTableViewCell.h"
|
||||
#import "FLEXNetworkTransactionCell.h"
|
||||
#import "FLEXNetworkTransaction.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXResources.h"
|
||||
|
||||
NSString *const kFLEXNetworkTransactionCellIdentifier = @"kFLEXNetworkTransactionCellIdentifier";
|
||||
|
||||
@interface FLEXNetworkTransactionTableViewCell ()
|
||||
@interface FLEXNetworkTransactionCell ()
|
||||
|
||||
@property (nonatomic) UIImageView *thumbnailImageView;
|
||||
@property (nonatomic) UILabel *nameLabel;
|
||||
@@ -23,7 +23,7 @@ NSString *const kFLEXNetworkTransactionCellIdentifier = @"kFLEXNetworkTransactio
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXNetworkTransactionTableViewCell
|
||||
@implementation FLEXNetworkTransactionCell
|
||||
|
||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// FLEXNetworkTransactionDetailTableViewController.h
|
||||
// FLEXNetworkTransactionDetailController.h
|
||||
// Flipboard
|
||||
//
|
||||
// Created by Ryan Olson on 2/10/15.
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
@class FLEXNetworkTransaction;
|
||||
|
||||
@interface FLEXNetworkTransactionDetailTableViewController : UITableViewController
|
||||
@interface FLEXNetworkTransactionDetailController : UITableViewController
|
||||
|
||||
@property (nonatomic) FLEXNetworkTransaction *transaction;
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// FLEXNetworkTransactionDetailTableViewController.m
|
||||
// FLEXNetworkTransactionDetailController.m
|
||||
// Flipboard
|
||||
//
|
||||
// Created by Ryan Olson on 2/10/15.
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#import "FLEXColor.h"
|
||||
#import "FLEXNetworkTransactionDetailTableViewController.h"
|
||||
#import "FLEXNetworkTransactionDetailController.h"
|
||||
#import "FLEXNetworkCurlLogger.h"
|
||||
#import "FLEXNetworkRecorder.h"
|
||||
#import "FLEXNetworkTransaction.h"
|
||||
@@ -44,13 +44,13 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
@end
|
||||
|
||||
@interface FLEXNetworkTransactionDetailTableViewController ()
|
||||
@interface FLEXNetworkTransactionDetailController ()
|
||||
|
||||
@property (nonatomic, copy) NSArray<FLEXNetworkDetailSection *> *sections;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXNetworkTransactionDetailTableViewController
|
||||
@implementation FLEXNetworkTransactionDetailController
|
||||
|
||||
- (instancetype)initWithStyle:(UITableViewStyle)style {
|
||||
// Force grouped style
|
||||
@@ -15,7 +15,7 @@
|
||||
#import "FLEXNetworkObserver.h"
|
||||
#import "FLEXNetworkRecorder.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "NSObject+Reflection.h"
|
||||
#import "NSObject+FLEX_Reflection.h"
|
||||
#import "FLEXMethod.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@@ -8,10 +8,22 @@
|
||||
|
||||
#import "FLEXRuntime+UIKitHelpers.h"
|
||||
|
||||
/// Carries state about the current user defaults settings
|
||||
@interface FLEXObjectExplorerDefaults : NSObject
|
||||
+ (instancetype)canEdit:(BOOL)editable wantsPreviews:(BOOL)showPreviews;
|
||||
|
||||
/// Only \c YES for properties and ivars
|
||||
@property (nonatomic, readonly) BOOL isEditable;
|
||||
/// Only affects properties and ivars
|
||||
@property (nonatomic, readonly) BOOL wantsDynamicPreviews;
|
||||
@end
|
||||
|
||||
@interface FLEXObjectExplorer : NSObject
|
||||
|
||||
+ (instancetype)forObject:(id)objectOrClass;
|
||||
|
||||
+ (void)configureDefaultsForItems:(NSArray<id<FLEXObjectExplorerItem>> *)items;
|
||||
|
||||
@property (nonatomic, readonly) id object;
|
||||
/// Subclasses can override to provide a more useful description
|
||||
@property (nonatomic, readonly) NSString *objectDescription;
|
||||
|
||||
@@ -9,14 +9,24 @@
|
||||
#import "FLEXObjectExplorer.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#import "NSObject+Reflection.h"
|
||||
#import "NSObject+FLEX_Reflection.h"
|
||||
#import "FLEXRuntime+Compare.h"
|
||||
#import "FLEXRuntime+UIKitHelpers.h"
|
||||
#import "FLEXPropertyAttributes.h"
|
||||
#import "NSObject+Reflection.h"
|
||||
#import "FLEXMetadataSection.h"
|
||||
#import "NSUserDefaults+FLEX.h"
|
||||
|
||||
@implementation FLEXObjectExplorerDefaults
|
||||
|
||||
+ (instancetype)canEdit:(BOOL)editable wantsPreviews:(BOOL)showPreviews {
|
||||
FLEXObjectExplorerDefaults *defaults = [self new];
|
||||
defaults->_isEditable = editable;
|
||||
defaults->_wantsDynamicPreviews = showPreviews;
|
||||
return defaults;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface FLEXObjectExplorer () {
|
||||
NSMutableArray<NSArray<FLEXProperty *> *> *_allProperties;
|
||||
NSMutableArray<NSArray<FLEXProperty *> *> *_allClassProperties;
|
||||
@@ -55,6 +65,24 @@
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
+ (void)configureDefaultsForItems:(NSArray<id<FLEXObjectExplorerItem>> *)items {
|
||||
BOOL hidePreviews = NSUserDefaults.standardUserDefaults.flex_explorerHidesVariablePreviews;
|
||||
FLEXObjectExplorerDefaults *mutable = [FLEXObjectExplorerDefaults
|
||||
canEdit:YES wantsPreviews:!hidePreviews
|
||||
];
|
||||
FLEXObjectExplorerDefaults *immutable = [FLEXObjectExplorerDefaults
|
||||
canEdit:NO wantsPreviews:!hidePreviews
|
||||
];
|
||||
|
||||
// .tag is used to cache whether the value of .isEditable;
|
||||
// This could change at runtime so it is important that
|
||||
// it is cached every time shortcuts are requeted and not
|
||||
// just once at as shortcuts are initially registered
|
||||
for (id<FLEXObjectExplorerItem> metadata in items) {
|
||||
metadata.defaults = metadata.isEditable ? mutable : immutable;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)objectDescription {
|
||||
if (!_objectDescription) {
|
||||
// Hard-code UIColor description
|
||||
@@ -224,9 +252,7 @@
|
||||
// because no other metadata types support editing.
|
||||
for (NSArray *matrix in @[_allProperties, _allIvars, /* _allMethods, _allClassMethods, _allConformedProtocols */]) {
|
||||
for (NSArray *metadataByClass in matrix) {
|
||||
for (id<FLEXRuntimeMetadata> metadata in metadataByClass) {
|
||||
metadata.tag = metadata.isEditable ? @YES : nil;
|
||||
}
|
||||
[FLEXObjectExplorer configureDefaultsForItems:metadataByClass];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
kFLEXDefaultsHidePropertyIvarsKey,
|
||||
kFLEXDefaultsHidePropertyMethodsKey,
|
||||
kFLEXDefaultsHideMethodOverridesKey,
|
||||
kFLEXDefaultsHideVariablePreviewsKey,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -101,7 +102,7 @@
|
||||
|
||||
// ... button for extra options
|
||||
[self addToolbarItems:@[[UIBarButtonItem
|
||||
itemWithImage:FLEXResources.moreIcon target:self action:@selector(moreButtonPressed)
|
||||
itemWithImage:FLEXResources.moreIcon target:self action:@selector(moreButtonPressed:)
|
||||
]]];
|
||||
|
||||
// Swipe gestures to swipe between classes in the hierarchy
|
||||
@@ -122,12 +123,7 @@
|
||||
//
|
||||
// "If your app targets iOS 9.0 and later or macOS 10.11 and later,
|
||||
// you don't need to unregister an observer in its dealloc method."
|
||||
NSArray<NSString *> *observedNotifications = @[
|
||||
kFLEXDefaultsHidePropertyIvarsKey,
|
||||
kFLEXDefaultsHidePropertyMethodsKey,
|
||||
kFLEXDefaultsHideMethodOverridesKey,
|
||||
];
|
||||
for (NSString *pref in observedNotifications) {
|
||||
for (NSString *pref in self.observedNotifications) {
|
||||
[NSNotificationCenter.defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(fullyReloadData)
|
||||
@@ -221,7 +217,7 @@
|
||||
[super reloadData];
|
||||
}
|
||||
|
||||
- (void)shareButtonPressed {
|
||||
- (void)shareButtonPressed:(UIBarButtonItem *)sender {
|
||||
[FLEXAlert makeSheet:^(FLEXAlert *make) {
|
||||
make.button(@"Add to Bookmarks").handler(^(NSArray<NSString *> *strings) {
|
||||
[FLEXBookmarkManager.bookmarks addObject:self.object];
|
||||
@@ -233,7 +229,7 @@
|
||||
UIPasteboard.generalPasteboard.string = [FLEXUtility addressOfObject:self.object];
|
||||
});
|
||||
make.button(@"Cancel").cancelStyle();
|
||||
} showFrom:self];
|
||||
} showFrom:self source:sender];
|
||||
}
|
||||
|
||||
|
||||
@@ -289,13 +285,14 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)moreButtonPressed {
|
||||
- (void)moreButtonPressed:(UIBarButtonItem *)sender {
|
||||
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
|
||||
// Maps preference keys to a description of what they affect
|
||||
NSDictionary<NSString *, NSString *> *explorerToggles = @{
|
||||
kFLEXDefaultsHidePropertyIvarsKey: @"Property-Backing Ivars",
|
||||
kFLEXDefaultsHidePropertyMethodsKey: @"Property-Backing Methods",
|
||||
kFLEXDefaultsHideMethodOverridesKey: @"Method Overrides",
|
||||
kFLEXDefaultsHidePropertyIvarsKey: @"Property-Backing Ivars",
|
||||
kFLEXDefaultsHidePropertyMethodsKey: @"Property-Backing Methods",
|
||||
kFLEXDefaultsHideMethodOverridesKey: @"Method Overrides",
|
||||
kFLEXDefaultsHideVariablePreviewsKey: @"Variable Previews"
|
||||
};
|
||||
|
||||
// Maps the key of the action itself to a map of a description
|
||||
@@ -303,9 +300,10 @@
|
||||
//
|
||||
// So keys that are hidden by default have NO mapped to "Show"
|
||||
NSDictionary<NSString *, NSDictionary *> *nextStateDescriptions = @{
|
||||
kFLEXDefaultsHidePropertyIvarsKey: @{ @NO: @"Hide ", @YES: @"Show " },
|
||||
kFLEXDefaultsHidePropertyMethodsKey: @{ @NO: @"Hide ", @YES: @"Show " },
|
||||
kFLEXDefaultsHideMethodOverridesKey: @{ @NO: @"Show ", @YES: @"Hide " },
|
||||
kFLEXDefaultsHidePropertyIvarsKey: @{ @NO: @"Hide ", @YES: @"Show " },
|
||||
kFLEXDefaultsHidePropertyMethodsKey: @{ @NO: @"Hide ", @YES: @"Show " },
|
||||
kFLEXDefaultsHideMethodOverridesKey: @{ @NO: @"Show ", @YES: @"Hide " },
|
||||
kFLEXDefaultsHideVariablePreviewsKey: @{ @NO: @"Hide ", @YES: @"Show " },
|
||||
};
|
||||
|
||||
[FLEXAlert makeSheet:^(FLEXAlert *make) {
|
||||
@@ -323,7 +321,7 @@
|
||||
}
|
||||
|
||||
make.button(@"Cancel").cancelStyle();
|
||||
} showFrom:self];
|
||||
} showFrom:self source:sender];
|
||||
}
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#import "FLEXFieldEditorViewController.h"
|
||||
#import "FLEXMethodCallingViewController.h"
|
||||
#import "FLEXIvar.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "FLEXRuntime+UIKitHelpers.h"
|
||||
|
||||
@interface FLEXMetadataSection ()
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
|
||||
#import "FLEXBundleShortcuts.h"
|
||||
#import "FLEXShortcut.h"
|
||||
#import "FLEXFileBrowserTableViewController.h"
|
||||
#import "FLEXAlert.h"
|
||||
#import "FLEXRuntimeExporter.h"
|
||||
#import "FLEXTableListViewController.h"
|
||||
#import "FLEXFileBrowserController.h"
|
||||
|
||||
#pragma mark -
|
||||
@implementation FLEXBundleShortcuts
|
||||
@@ -16,15 +19,95 @@
|
||||
|
||||
+ (instancetype)forObject:(NSBundle *)bundle {
|
||||
return [self forObject:bundle additionalRows:@[
|
||||
[FLEXActionShortcut title:@"Browse Bundle Directory" subtitle:nil
|
||||
viewer:^UIViewController *(id view) {
|
||||
return [FLEXFileBrowserTableViewController path:bundle.bundlePath];
|
||||
[FLEXActionShortcut
|
||||
title:@"Browse Bundle Directory" subtitle:nil
|
||||
viewer:^UIViewController *(NSBundle *bundle) {
|
||||
return [FLEXFileBrowserController path:bundle.bundlePath];
|
||||
}
|
||||
accessoryType:^UITableViewCellAccessoryType(id view) {
|
||||
accessoryType:^UITableViewCellAccessoryType(NSBundle *bundle) {
|
||||
return UITableViewCellAccessoryDisclosureIndicator;
|
||||
}
|
||||
]
|
||||
],
|
||||
[FLEXActionShortcut title:@"Browse Bundle as Database…" subtitle:nil
|
||||
selectionHandler:^(UIViewController *host, NSBundle *bundle) {
|
||||
[self promptToExportBundleAsDatabase:bundle host:host];
|
||||
}
|
||||
accessoryType:^UITableViewCellAccessoryType(NSBundle *bundle) {
|
||||
return UITableViewCellAccessoryDisclosureIndicator;
|
||||
}
|
||||
],
|
||||
]];
|
||||
}
|
||||
|
||||
+ (void)promptToExportBundleAsDatabase:(NSBundle *)bundle host:(UIViewController *)host {
|
||||
[FLEXAlert makeAlert:^(FLEXAlert *make) {
|
||||
make.title(@"Save As…").message(
|
||||
@"The database be saved in the Library folder. "
|
||||
"Depending on the number of classes, it may take "
|
||||
"10 minutes or more to finish exporting. 20,000 "
|
||||
"classes takes about 7 minutes."
|
||||
);
|
||||
make.configuredTextField(^(UITextField *field) {
|
||||
field.placeholder = @"FLEXRuntimeExport.objc.db";
|
||||
field.text = [NSString stringWithFormat:
|
||||
@"%@.objc.db", bundle.executablePath.lastPathComponent
|
||||
];
|
||||
});
|
||||
make.button(@"Start").handler(^(NSArray<NSString *> *strings) {
|
||||
[self browseBundleAsDatabase:bundle host:host name:strings[0]];
|
||||
});
|
||||
make.button(@"Cancel").cancelStyle();
|
||||
} showFrom:host];
|
||||
}
|
||||
|
||||
+ (void)browseBundleAsDatabase:(NSBundle *)bundle host:(UIViewController *)host name:(NSString *)name {
|
||||
NSParameterAssert(name.length);
|
||||
|
||||
UIAlertController *progress = [FLEXAlert makeAlert:^(FLEXAlert *make) {
|
||||
make.title(@"Generating Database");
|
||||
// Some iOS version glitch out of there is
|
||||
// no initial message and you add one later
|
||||
make.message(@"…");
|
||||
}];
|
||||
|
||||
[host presentViewController:progress animated:YES completion:^{
|
||||
// Generate path to store db
|
||||
NSString *path = [NSSearchPathForDirectoriesInDomains(
|
||||
NSLibraryDirectory, NSUserDomainMask, YES
|
||||
)[0] stringByAppendingPathComponent:name];
|
||||
|
||||
progress.message = [path stringByAppendingString:@"\n\nCreating database…"];
|
||||
|
||||
// Generate db and show progress
|
||||
[FLEXRuntimeExporter createRuntimeDatabaseAtPath:path
|
||||
forImages:@[bundle.executablePath]
|
||||
progressHandler:^(NSString *status) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
progress.message = [progress.message
|
||||
stringByAppendingFormat:@"\n%@", status
|
||||
];
|
||||
[progress.view setNeedsLayout];
|
||||
[progress.view layoutIfNeeded];
|
||||
});
|
||||
} completion:^(NSString *error) {
|
||||
// Display error if any
|
||||
if (error) {
|
||||
progress.title = @"Error";
|
||||
progress.message = error;
|
||||
[progress addAction:[UIAlertAction
|
||||
actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]
|
||||
];
|
||||
}
|
||||
// Browse database
|
||||
else {
|
||||
[progress dismissViewControllerAnimated:YES completion:nil];
|
||||
[host.navigationController pushViewController:[
|
||||
[FLEXTableListViewController alloc] initWithPath:path
|
||||
] animated:YES];
|
||||
}
|
||||
}
|
||||
];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#import "FLEXShortcut.h"
|
||||
#import "FLEXObjectExplorerFactory.h"
|
||||
#import "FLEXObjectListViewController.h"
|
||||
#import "NSObject+Reflection.h"
|
||||
#import "NSObject+FLEX_Reflection.h"
|
||||
|
||||
@interface FLEXClassShortcuts ()
|
||||
@property (nonatomic, readonly) Class cls;
|
||||
|
||||
@@ -8,57 +8,60 @@
|
||||
|
||||
#import "FLEXImageShortcuts.h"
|
||||
#import "FLEXImagePreviewViewController.h"
|
||||
#import "FLEXShortcut.h"
|
||||
#import "FLEXAlert.h"
|
||||
|
||||
@interface FLEXImageShortcuts ()
|
||||
@property (nonatomic, readonly) UIImage *image;
|
||||
@interface UIAlertController (FLEXImageShortcuts)
|
||||
- (void)flex_image:(UIImage *)image disSaveWithError:(NSError *)error :(void *)context;
|
||||
@end
|
||||
|
||||
@implementation FLEXImageShortcuts
|
||||
|
||||
#pragma mark - Internal
|
||||
|
||||
- (UIImage *)image {
|
||||
return self.object;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Overrides
|
||||
|
||||
+ (instancetype)forObject:(UIImage *)image {
|
||||
// These additional rows will appear at the beginning of the shortcuts section.
|
||||
// The methods below are written in such a way that they will not interfere
|
||||
// with properties/etc being registered alongside these
|
||||
return [self forObject:image additionalRows:@[@"View Image", @"Save Image"]];
|
||||
}
|
||||
|
||||
/// View image
|
||||
- (UIViewController *)viewControllerToPushForRow:(NSInteger)row {
|
||||
if (row == 0) {
|
||||
return [FLEXImagePreviewViewController forImage:self.image];
|
||||
}
|
||||
|
||||
return [super viewControllerToPushForRow:row];
|
||||
}
|
||||
|
||||
/// Save image
|
||||
- (void (^)(__kindof UIViewController *))didSelectRowAction:(NSInteger)row {
|
||||
if (row == 1) {
|
||||
return ^(UIViewController *host) {
|
||||
UIImageWriteToSavedPhotosAlbum(self.image, nil, nil, nil);
|
||||
};
|
||||
}
|
||||
|
||||
return [super didSelectRowAction:row];
|
||||
}
|
||||
|
||||
/// "Save Image" does not need a disclosure indicator
|
||||
- (UITableViewCellAccessoryType)accessoryTypeForRow:(NSInteger)row {
|
||||
switch (row) {
|
||||
case 0: return UITableViewCellAccessoryDisclosureIndicator;
|
||||
case 1: return UITableViewCellAccessoryNone;
|
||||
default: return [super accessoryTypeForRow:row];
|
||||
}
|
||||
return [self forObject:image additionalRows:@[
|
||||
[FLEXActionShortcut title:@"View Image" subtitle:nil
|
||||
viewer:^UIViewController *(id image) {
|
||||
return [FLEXImagePreviewViewController forImage:image];
|
||||
}
|
||||
accessoryType:^UITableViewCellAccessoryType(id image) {
|
||||
return UITableViewCellAccessoryDisclosureIndicator;
|
||||
}
|
||||
],
|
||||
[FLEXActionShortcut title:@"Save Image" subtitle:nil
|
||||
selectionHandler:^(UIViewController *host, id image) {
|
||||
// Present modal alerting user about saving
|
||||
UIAlertController *alert = [FLEXAlert makeAlert:^(FLEXAlert *make) {
|
||||
make.title(@"Saving Image…");
|
||||
}];
|
||||
[host presentViewController:alert animated:YES completion:nil];
|
||||
|
||||
// Save the image
|
||||
UIImageWriteToSavedPhotosAlbum(
|
||||
image, alert, @selector(flex_image:disSaveWithError::), nil
|
||||
);
|
||||
}
|
||||
accessoryType:^UITableViewCellAccessoryType(id image) {
|
||||
return UITableViewCellAccessoryDisclosureIndicator;
|
||||
}
|
||||
]
|
||||
]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation UIAlertController (FLEXImageShortcuts)
|
||||
|
||||
- (void)flex_image:(UIImage *)image disSaveWithError:(NSError *)error :(void *)context {
|
||||
self.title = @"Image Saved";
|
||||
flex_dispatch_after(1, dispatch_get_main_queue(), ^{
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright © 2019 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "FLEXObjectExplorer.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
///
|
||||
/// It is useful to make your own shortcuts to append/prepend
|
||||
/// them to the existing list of shortcuts for a class.
|
||||
@protocol FLEXShortcut <NSObject>
|
||||
@protocol FLEXShortcut <FLEXObjectExplorerItem>
|
||||
|
||||
- (nonnull NSString *)titleWith:(id)object;
|
||||
- (nullable NSString *)subtitleWith:(id)object;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
@end
|
||||
|
||||
@implementation FLEXShortcut
|
||||
@synthesize defaults = _defaults;
|
||||
|
||||
+ (id<FLEXShortcut>)shortcutFor:(id)item {
|
||||
if ([item conformsToProtocol:@protocol(FLEXShortcut)]) {
|
||||
@@ -85,7 +86,7 @@
|
||||
|
||||
- (NSString *)subtitleWith:(id)object {
|
||||
if (self.metadataKind) {
|
||||
return [self.metadata previewWithTarget:object] ?: @"nil";
|
||||
return [self.metadata previewWithTarget:object];
|
||||
}
|
||||
|
||||
// Item is probably a string; must return empty string since
|
||||
@@ -124,6 +125,32 @@
|
||||
return kFLEXMultilineCell;
|
||||
}
|
||||
|
||||
#pragma mark FLEXObjectExplorerDefaults
|
||||
|
||||
- (void)setDefaults:(FLEXObjectExplorerDefaults *)defaults {
|
||||
_defaults = defaults;
|
||||
|
||||
if (_metadataKind) {
|
||||
self.metadata.defaults = defaults;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isEditable {
|
||||
if (_metadataKind) {
|
||||
return self.metadata.isEditable;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isCallable {
|
||||
if (_metadataKind) {
|
||||
return self.metadata.isCallable;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
- (FLEXProperty *)property { return _item; }
|
||||
@@ -145,6 +172,7 @@
|
||||
@end
|
||||
|
||||
@implementation FLEXActionShortcut
|
||||
@synthesize defaults = _defaults;
|
||||
|
||||
+ (instancetype)title:(NSString *)title
|
||||
subtitle:(NSString *(^)(id))subtitle
|
||||
@@ -186,7 +214,11 @@
|
||||
}
|
||||
|
||||
- (NSString *)subtitleWith:(id)object {
|
||||
return self.subtitleFuture(object);
|
||||
if (self.defaults.wantsDynamicPreviews) {
|
||||
return self.subtitleFuture(object);
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void (^)(UIViewController *))didSelectActionWith:(id)object {
|
||||
@@ -216,4 +248,7 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)isEditable { return NO; }
|
||||
- (BOOL)isCallable { return NO; }
|
||||
|
||||
@end
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#import "FLEXShortcutsFactory+Defaults.h"
|
||||
#import "FLEXShortcut.h"
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#import "NSObject+Reflection.h"
|
||||
#import "NSObject+FLEX_Reflection.h"
|
||||
|
||||
#pragma mark - Views
|
||||
|
||||
@@ -90,6 +90,13 @@
|
||||
@"currentTitle", @"currentImage", @"enabled", @"frame",
|
||||
@"superview", @"subviews"
|
||||
]).forClass(UIButton.class);
|
||||
|
||||
// UIImageView
|
||||
self.append.properties(@[
|
||||
@"image", @"animationImages", @"frame", @"bounds", @"center",
|
||||
@"transform", @"alpha", @"hidden", @"clipsToBounds",
|
||||
@"userInteractionEnabled", @"layer", @"superview", @"subviews",
|
||||
]).forClass(UIImageView.class);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#import "FLEXIvar.h"
|
||||
#import "FLEXMethod.h"
|
||||
#import "FLEXRuntime+UIKitHelpers.h"
|
||||
#import "FLEXObjectExplorer.h"
|
||||
|
||||
#pragma mark Private
|
||||
|
||||
@@ -86,6 +87,7 @@
|
||||
return [FLEXShortcut shortcutFor:obj];
|
||||
}];
|
||||
_numberOfLines = 1;
|
||||
|
||||
// Populate titles and subtitles
|
||||
[self reloadData];
|
||||
}
|
||||
@@ -156,6 +158,8 @@
|
||||
}
|
||||
|
||||
- (void)reloadData {
|
||||
[FLEXObjectExplorer configureDefaultsForItems:self.allShortcuts];
|
||||
|
||||
// Generate all (sub)titles from shortcuts
|
||||
if (self.allShortcuts) {
|
||||
self.allTitles = [self.allShortcuts flex_mapped:^id(FLEXShortcut *s, NSUInteger idx) {
|
||||
@@ -303,15 +307,8 @@ static RegistrationBuckets *mMethods = nil;
|
||||
classKey = class_getSuperclass(classKey);
|
||||
}
|
||||
}
|
||||
|
||||
// .tag is used to cache whether the value of .isEditable;
|
||||
// This could change at runtime so it is important that
|
||||
// it is cached every time shortcuts are requeted and not
|
||||
// just once at as shortcuts are initially registered
|
||||
for (id<FLEXRuntimeMetadata> metadata in shortcuts) {
|
||||
metadata.tag = metadata.isEditable ? @YES : nil;
|
||||
}
|
||||
|
||||
|
||||
[FLEXObjectExplorer configureDefaultsForItems:shortcuts];
|
||||
return shortcuts;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
+ (instancetype)forObject:(UIViewController *)viewController {
|
||||
BOOL (^vcIsInuse)(UIViewController *) = ^BOOL(UIViewController *controller) {
|
||||
if (controller.view.window) {
|
||||
if (controller.viewIfLoaded.window) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,15 +12,25 @@
|
||||
#import "FLEXMethod.h"
|
||||
#import "FLEXProtocol.h"
|
||||
|
||||
@protocol FLEXRuntimeMetadata <NSObject>
|
||||
/// Used as the main title of the row
|
||||
- (NSString *)description;
|
||||
/// Used to compare metadata objects for uniqueness
|
||||
@property (nonatomic, readonly) NSString *name;
|
||||
@class FLEXObjectExplorerDefaults;
|
||||
|
||||
/// Model objects of an object explorer screen adopt this
|
||||
/// protocol in order respond to user defaults changes
|
||||
@protocol FLEXObjectExplorerItem <NSObject>
|
||||
/// Current explorer settings. Set when settings change.
|
||||
@property (nonatomic) FLEXObjectExplorerDefaults *defaults;
|
||||
|
||||
/// YES for properties and ivars which surely support editing, NO for all methods.
|
||||
@property (nonatomic, readonly) BOOL isEditable;
|
||||
/// NO for ivars, YES for supported methods and properties
|
||||
@property (nonatomic, readonly) BOOL isCallable;
|
||||
@end
|
||||
|
||||
@protocol FLEXRuntimeMetadata <FLEXObjectExplorerItem>
|
||||
/// Used as the main title of the row
|
||||
- (NSString *)description;
|
||||
/// Used to compare metadata objects for uniqueness
|
||||
@property (nonatomic, readonly) NSString *name;
|
||||
|
||||
/// For internal use
|
||||
@property (nonatomic) id tag;
|
||||
@@ -76,3 +86,7 @@ typedef NS_ENUM(NSUInteger, FLEXStaticMetadataRowStyle) {
|
||||
+ (NSArray<FLEXStaticMetadata *> *)classHierarchy:(NSArray<Class> *)classes;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/// This is assigned to the \c tag property of each metadata.
|
||||
|
||||
|
||||
@@ -15,11 +15,21 @@
|
||||
#import "FLEXMethodCallingViewController.h"
|
||||
#import "FLEXTableView.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "NSString+FLEX.h"
|
||||
|
||||
#define FLEXObjectExplorerDefaultsImpl \
|
||||
- (FLEXObjectExplorerDefaults *)defaults { \
|
||||
return self.tag; \
|
||||
} \
|
||||
\
|
||||
- (void)setDefaults:(FLEXObjectExplorerDefaults *)defaults { \
|
||||
self.tag = defaults; \
|
||||
}
|
||||
|
||||
#pragma mark FLEXProperty
|
||||
@implementation FLEXProperty (UIKitHelpers)
|
||||
FLEXObjectExplorerDefaultsImpl
|
||||
|
||||
/// Decide whether to use potentialTarget or [potentialTarget class] to get or set property
|
||||
- (id)appropriateTargetForPropertyType:(id)potentialTarget {
|
||||
@@ -67,11 +77,13 @@
|
||||
- (NSString *)previewWithTarget:(id)object {
|
||||
if (object_isClass(object) && !self.isClassProperty) {
|
||||
return self.attributes.fullDeclaration;
|
||||
} else {
|
||||
} else if (self.defaults.wantsDynamicPreviews) {
|
||||
return [FLEXRuntimeUtility
|
||||
summaryForObject:[self currentValueWithTarget:object]
|
||||
];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UIViewController *)viewerWithTarget:(id)object {
|
||||
@@ -94,7 +106,7 @@
|
||||
// We use .tag to store the cached value of .isEditable that is
|
||||
// initialized by FLEXObjectExplorer in -reloadMetada
|
||||
if ([self getPotentiallyUnboxedValue:targetForValueCheck]) {
|
||||
if (self.tag) {
|
||||
if (self.defaults.isEditable) {
|
||||
// Editable non-nil value, both
|
||||
return UITableViewCellAccessoryDetailDisclosureButton;
|
||||
} else {
|
||||
@@ -102,7 +114,7 @@
|
||||
return UITableViewCellAccessoryDisclosureIndicator;
|
||||
}
|
||||
} else {
|
||||
if (self.tag) {
|
||||
if (self.defaults.isEditable) {
|
||||
// Editable nil value, just (i)
|
||||
return UITableViewCellAccessoryDetailButton;
|
||||
} else {
|
||||
@@ -177,6 +189,7 @@
|
||||
|
||||
#pragma mark FLEXIvar
|
||||
@implementation FLEXIvar (UIKitHelpers)
|
||||
FLEXObjectExplorerDefaultsImpl
|
||||
|
||||
- (BOOL)isEditable {
|
||||
const FLEXTypeEncoding *typeEncoding = self.typeEncoding.UTF8String;
|
||||
@@ -198,10 +211,13 @@
|
||||
- (NSString *)previewWithTarget:(id)object {
|
||||
if (object_isClass(object)) {
|
||||
return self.details;
|
||||
} else if (self.defaults.wantsDynamicPreviews) {
|
||||
return [FLEXRuntimeUtility
|
||||
summaryForObject:[self currentValueWithTarget:object]
|
||||
];
|
||||
}
|
||||
return [FLEXRuntimeUtility
|
||||
summaryForObject:[self currentValueWithTarget:object]
|
||||
];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UIViewController *)viewerWithTarget:(id)object {
|
||||
@@ -222,7 +238,7 @@
|
||||
|
||||
// Could use .isEditable here, but we use .tag for speed since it is cached
|
||||
if ([self getPotentiallyUnboxedValue:object]) {
|
||||
if (self.tag) {
|
||||
if (self.defaults.isEditable) {
|
||||
// Editable non-nil value, both
|
||||
return UITableViewCellAccessoryDetailDisclosureButton;
|
||||
} else {
|
||||
@@ -230,7 +246,7 @@
|
||||
return UITableViewCellAccessoryDisclosureIndicator;
|
||||
}
|
||||
} else {
|
||||
if (self.tag) {
|
||||
if (self.defaults.isEditable) {
|
||||
// Editable nil value, just (i)
|
||||
return UITableViewCellAccessoryDetailButton;
|
||||
} else {
|
||||
@@ -301,6 +317,7 @@
|
||||
|
||||
#pragma mark FLEXMethod
|
||||
@implementation FLEXMethodBase (UIKitHelpers)
|
||||
FLEXObjectExplorerDefaultsImpl
|
||||
|
||||
- (BOOL)isEditable {
|
||||
return NO;
|
||||
@@ -402,6 +419,7 @@
|
||||
|
||||
#pragma mark FLEXProtocol
|
||||
@implementation FLEXProtocol (UIKitHelpers)
|
||||
FLEXObjectExplorerDefaultsImpl
|
||||
|
||||
- (BOOL)isEditable {
|
||||
return NO;
|
||||
@@ -475,6 +493,8 @@
|
||||
@synthesize name = _name;
|
||||
@synthesize tag = _tag;
|
||||
|
||||
FLEXObjectExplorerDefaultsImpl
|
||||
|
||||
+ (NSArray<FLEXStaticMetadata *> *)classHierarchy:(NSArray<Class> *)classes {
|
||||
return [classes flex_mapped:^id(Class cls, NSUInteger idx) {
|
||||
return [FLEXStaticMetadata_Class withClass:cls];
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// NSArray+Functional.h
|
||||
// NSArray+FLEX.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner Bennett on 9/25/19.
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
//
|
||||
// NSArray+Functional.m
|
||||
// NSArray+FLEX.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner Bennett on 9/25/19.
|
||||
// Copyright © 2019 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
|
||||
#define FLEXArrayClassIsMutable(me) ([[self class] isSubclassOfClass:[NSMutableArray class]])
|
||||
|
||||
+12
-1
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// NSObject+Reflection.h
|
||||
// NSObject+FLEX_Reflection.h
|
||||
// FLEX
|
||||
//
|
||||
// Derived from MirrorKit.
|
||||
@@ -25,6 +25,17 @@ NSArray<Class> *FLEXGetAllSubclasses(_Nullable Class cls, BOOL includeSelf);
|
||||
NSArray<Class> *FLEXGetClassHierarchy(_Nullable Class cls, BOOL includeSelf);
|
||||
NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(_Nullable Class cls);
|
||||
|
||||
NSArray<FLEXIvar *> *FLEXGetAllIvars(_Nullable Class cls);
|
||||
/// @param cls a class object to get instance properties,
|
||||
/// or a metaclass object to get class properties
|
||||
NSArray<FLEXProperty *> *FLEXGetAllProperties(_Nullable Class cls);
|
||||
/// @param cls a class object to get instance methods,
|
||||
/// or a metaclass object to get class methods
|
||||
/// @param instance used to mark methods as instance methods or not.
|
||||
/// Not used to determine whether to get instance or class methods.
|
||||
NSArray<FLEXMethod *> *FLEXGetAllMethods(_Nullable Class cls, BOOL instance);
|
||||
|
||||
|
||||
|
||||
#pragma mark Reflection
|
||||
@interface NSObject (Reflection)
|
||||
+54
-62
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// NSObject+Reflection.m
|
||||
// NSObject+FLEX_Reflection.m
|
||||
// FLEX
|
||||
//
|
||||
// Derived from MirrorKit.
|
||||
@@ -7,7 +7,7 @@
|
||||
// Copyright (c) 2015 Tanner Bennett. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+Reflection.h"
|
||||
#import "NSObject+FLEX_Reflection.h"
|
||||
#import "FLEXClassBuilder.h"
|
||||
#import "FLEXMirror.h"
|
||||
#import "FLEXProperty.h"
|
||||
@@ -15,7 +15,7 @@
|
||||
#import "FLEXIvar.h"
|
||||
#import "FLEXProtocol.h"
|
||||
#import "FLEXPropertyAttributes.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "FLEXUtility.h"
|
||||
|
||||
|
||||
@@ -101,6 +101,45 @@ NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(Class cls) {
|
||||
}];
|
||||
}
|
||||
|
||||
NSArray<FLEXIvar *> *FLEXGetAllIvars(_Nullable Class cls) {
|
||||
if (!cls) return nil;
|
||||
|
||||
unsigned int ivcount;
|
||||
Ivar *objcivars = class_copyIvarList(cls, &ivcount);
|
||||
NSArray *ivars = [NSArray flex_forEachUpTo:ivcount map:^id(NSUInteger i) {
|
||||
return [FLEXIvar ivar:objcivars[i]];
|
||||
}];
|
||||
|
||||
free(objcivars);
|
||||
return ivars;
|
||||
}
|
||||
|
||||
NSArray<FLEXProperty *> *FLEXGetAllProperties(_Nullable Class cls) {
|
||||
if (!cls) return nil;
|
||||
|
||||
unsigned int pcount;
|
||||
objc_property_t *objcproperties = class_copyPropertyList(cls, &pcount);
|
||||
NSArray *properties = [NSArray flex_forEachUpTo:pcount map:^id(NSUInteger i) {
|
||||
return [FLEXProperty property:objcproperties[i] onClass:cls];
|
||||
}];
|
||||
|
||||
free(objcproperties);
|
||||
return properties;
|
||||
}
|
||||
|
||||
NSArray<FLEXMethod *> *FLEXGetAllMethods(_Nullable Class cls, BOOL instance) {
|
||||
if (!cls) return nil;
|
||||
|
||||
unsigned int mcount;
|
||||
Method *objcmethods = class_copyMethodList(cls, &mcount);
|
||||
NSArray *methods = [NSArray flex_forEachUpTo:mcount map:^id(NSUInteger i) {
|
||||
return [FLEXMethod method:objcmethods[i] isInstanceMethod:instance];
|
||||
}];
|
||||
|
||||
free(objcmethods);
|
||||
return methods;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark NSProxy
|
||||
|
||||
@@ -135,6 +174,11 @@ NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(Class cls) {
|
||||
FLEXClassBuilder *swiftObjectMeta = [FLEXClassBuilder builderForClass:SwiftObject_meta];
|
||||
[swiftObject addMethods:instanceMethods];
|
||||
[swiftObjectMeta addMethods:classMethods];
|
||||
|
||||
// So we can put Swift objects into dictionaries...
|
||||
[swiftObjectMeta addMethods:@[
|
||||
[NSObject flex_classMethodNamed:@"copyWithZone:"]]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,41 +236,17 @@ NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(Class cls) {
|
||||
@implementation NSObject (Methods)
|
||||
|
||||
+ (NSArray<FLEXMethod *> *)flex_allMethods {
|
||||
NSMutableArray *instanceMethods = (id)self.flex_allInstanceMethods;
|
||||
NSMutableArray *instanceMethods = self.flex_allInstanceMethods.mutableCopy;
|
||||
[instanceMethods addObjectsFromArray:self.flex_allClassMethods];
|
||||
return instanceMethods;
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXMethod *> *)flex_allInstanceMethods {
|
||||
unsigned int mcount;
|
||||
Method *objcmethods = class_copyMethodList([self class], &mcount);
|
||||
|
||||
NSMutableArray *methods = [NSMutableArray new];
|
||||
for (int i = 0; i < mcount; i++) {
|
||||
FLEXMethod *m = [FLEXMethod method:objcmethods[i] isInstanceMethod:YES];
|
||||
if (m) {
|
||||
[methods addObject:m];
|
||||
}
|
||||
}
|
||||
|
||||
free(objcmethods);
|
||||
return methods;
|
||||
return FLEXGetAllMethods(self, YES);
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXMethod *> *)flex_allClassMethods {
|
||||
unsigned int mcount;
|
||||
Method *objcmethods = class_copyMethodList(self.flex_metaclass, &mcount);
|
||||
|
||||
NSMutableArray *methods = [NSMutableArray new];
|
||||
for (int i = 0; i < mcount; i++) {
|
||||
FLEXMethod *m = [FLEXMethod method:objcmethods[i] isInstanceMethod:NO];
|
||||
if (m) {
|
||||
[methods addObject:m];
|
||||
}
|
||||
}
|
||||
|
||||
free(objcmethods);
|
||||
return methods;
|
||||
return FLEXGetAllMethods(self.flex_metaclass, NO);
|
||||
}
|
||||
|
||||
+ (FLEXMethod *)flex_methodNamed:(NSString *)name {
|
||||
@@ -292,16 +312,7 @@ NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(Class cls) {
|
||||
@implementation NSObject (Ivars)
|
||||
|
||||
+ (NSArray<FLEXIvar *> *)flex_allIvars {
|
||||
unsigned int ivcount;
|
||||
Ivar *objcivars = class_copyIvarList([self class], &ivcount);
|
||||
|
||||
NSMutableArray *ivars = [NSMutableArray new];
|
||||
for (int i = 0; i < ivcount; i++) {
|
||||
[ivars addObject:[FLEXIvar ivar:objcivars[i]]];
|
||||
}
|
||||
|
||||
free(objcivars);
|
||||
return ivars;
|
||||
return FLEXGetAllIvars(self);
|
||||
}
|
||||
|
||||
+ (FLEXIvar *)flex_ivarNamed:(NSString *)name {
|
||||
@@ -373,36 +384,17 @@ NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(Class cls) {
|
||||
@implementation NSObject (Properties)
|
||||
|
||||
+ (NSArray<FLEXProperty *> *)flex_allProperties {
|
||||
NSMutableArray *instanceProperties = (id)self.flex_allInstanceProperties;
|
||||
NSMutableArray *instanceProperties = self.flex_allInstanceProperties.mutableCopy;
|
||||
[instanceProperties addObjectsFromArray:self.flex_allClassProperties];
|
||||
return instanceProperties;
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXProperty *> *)flex_allInstanceProperties {
|
||||
unsigned int pcount;
|
||||
objc_property_t *objcproperties = class_copyPropertyList(self, &pcount);
|
||||
|
||||
NSMutableArray *properties = [NSMutableArray new];
|
||||
for (int i = 0; i < pcount; i++) {
|
||||
[properties addObject:[FLEXProperty property:objcproperties[i] onClass:self]];
|
||||
}
|
||||
|
||||
free(objcproperties);
|
||||
return properties;
|
||||
return FLEXGetAllProperties(self);
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXProperty *> *)flex_allClassProperties {
|
||||
Class metaclass = self.flex_metaclass;
|
||||
unsigned int pcount;
|
||||
objc_property_t *objcproperties = class_copyPropertyList(metaclass, &pcount);
|
||||
|
||||
NSMutableArray *properties = [NSMutableArray new];
|
||||
for (int i = 0; i < pcount; i++) {
|
||||
[properties addObject:[FLEXProperty property:objcproperties[i] onClass:metaclass]];
|
||||
}
|
||||
|
||||
free(objcproperties);
|
||||
return properties;
|
||||
return FLEXGetAllProperties(self.flex_metaclass);
|
||||
}
|
||||
|
||||
+ (FLEXProperty *)flex_propertyNamed:(NSString *)name {
|
||||
+1
@@ -8,6 +8,7 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef void (^VoidBlock)(void);
|
||||
|
||||
@interface NSTimer (Blocks)
|
||||
|
||||
+ (instancetype)fireSecondsFromNow:(NSTimeInterval)delay block:(VoidBlock)block;
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
// Created by Tanner on 3/23/17.
|
||||
//
|
||||
|
||||
#import "NSTimer+Blocks.h"
|
||||
#import "NSTimer+FLEX.h"
|
||||
|
||||
@interface Block : NSObject
|
||||
- (void)invoke;
|
||||
@@ -8,31 +8,37 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// Only use these if the getters and setters aren't good enough for whatever reaso
|
||||
// Only use these if the getters and setters aren't good enough for whatever reason
|
||||
extern NSString * const kFLEXDefaultsToolbarTopMarginKey;
|
||||
extern NSString * const kFLEXDefaultsiOSPersistentOSLogKey;
|
||||
extern NSString * const kFLEXDefaultsHidePropertyIvarsKey;
|
||||
extern NSString * const kFLEXDefaultsHidePropertyMethodsKey;
|
||||
extern NSString * const kFLEXDefaultsHideMethodOverridesKey;
|
||||
extern NSString * const kFLEXDefaultsHideVariablePreviewsKey;
|
||||
extern NSString * const kFLEXDefaultsNetworkHostBlacklistKey;
|
||||
extern NSString * const kFLEXDefaultsDisableOSLogForceASLKey;
|
||||
extern NSString * const kFLEXDefaultsRegisterJSONExplorerKey;
|
||||
|
||||
/// All BOOL preferences are NO by default
|
||||
@interface NSUserDefaults (FLEX)
|
||||
|
||||
- (void)toggleBoolForKey:(NSString *)key;
|
||||
|
||||
@property (nonatomic) double flex_toolbarTopMargin;
|
||||
|
||||
/// NO by default
|
||||
@property (nonatomic) BOOL flex_cacheOSLogMessages;
|
||||
|
||||
/// NO by default
|
||||
@property (nonatomic) BOOL flex_explorerHidesPropertyIvars;
|
||||
/// NO by default
|
||||
@property (nonatomic) BOOL flex_explorerHidesPropertyMethods;
|
||||
/// NO by default
|
||||
@property (nonatomic) BOOL flex_explorerShowsMethodOverrides;
|
||||
|
||||
// Not actually stored in defaults, but written to a file
|
||||
@property (nonatomic) NSArray<NSString *> *flex_networkHostBlacklist;
|
||||
|
||||
/// Whether or not to register the object explorer as a JSON viewer on launch
|
||||
@property (nonatomic) BOOL flex_registerDictionaryJSONViewerOnLaunch;
|
||||
|
||||
/// Disable os_log and re-enable ASL. May break Console.app output.
|
||||
@property (nonatomic) BOOL flex_disableOSLog;
|
||||
@property (nonatomic) BOOL flex_cacheOSLogMessages;
|
||||
|
||||
@property (nonatomic) BOOL flex_explorerHidesPropertyIvars;
|
||||
@property (nonatomic) BOOL flex_explorerHidesPropertyMethods;
|
||||
@property (nonatomic) BOOL flex_explorerShowsMethodOverrides;
|
||||
@property (nonatomic) BOOL flex_explorerHidesVariablePreviews;
|
||||
|
||||
@end
|
||||
|
||||
@@ -13,17 +13,22 @@ NSString * const kFLEXDefaultsiOSPersistentOSLogKey = @"com.flipborad.flex.enabl
|
||||
NSString * const kFLEXDefaultsHidePropertyIvarsKey = @"com.flipboard.FLEX.hide_property_ivars";
|
||||
NSString * const kFLEXDefaultsHidePropertyMethodsKey = @"com.flipboard.FLEX.hide_property_methods";
|
||||
NSString * const kFLEXDefaultsHideMethodOverridesKey = @"com.flipboard.FLEX.hide_method_overrides";
|
||||
NSString * const kFLEXDefaultsHideVariablePreviewsKey = @"com.flipboard.FLEX.hide_variable_previews";
|
||||
NSString * const kFLEXDefaultsNetworkHostBlacklistKey = @"com.flipboard.FLEX.network_host_blacklist";
|
||||
NSString * const kFLEXDefaultsDisableOSLogForceASLKey = @"com.flipboard.FLEX.try_disable_os_log";
|
||||
NSString * const kFLEXDefaultsRegisterJSONExplorerKey = @"com.flipboard.FLEX.view_json_as_object";
|
||||
|
||||
#define FLEXDefaultsPathForFile(name) ({ \
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains( \
|
||||
NSLibraryDirectory, NSUserDomainMask, NO \
|
||||
NSLibraryDirectory, NSUserDomainMask, YES \
|
||||
); \
|
||||
[paths[0] stringByAppendingPathComponent:@"Preferences"]; \
|
||||
})
|
||||
|
||||
@implementation NSUserDefaults (FLEX)
|
||||
|
||||
#pragma mark Internal
|
||||
|
||||
/// @param filename the name of a plist file without any extension
|
||||
- (NSString *)flex_defaultsPathForFile:(NSString *)filename {
|
||||
filename = [filename stringByAppendingPathExtension:@"plist"];
|
||||
@@ -35,11 +40,15 @@ NSString * const kFLEXDefaultsNetworkHostBlacklistKey = @"com.flipboard.FLEX.net
|
||||
return [preferences stringByAppendingPathComponent:filename];
|
||||
}
|
||||
|
||||
#pragma mark Helper
|
||||
|
||||
- (void)toggleBoolForKey:(NSString *)key {
|
||||
[self setBool:![self boolForKey:key] forKey:key];
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:key object:nil];
|
||||
}
|
||||
|
||||
#pragma mark Misc
|
||||
|
||||
- (double)flex_toolbarTopMargin {
|
||||
if ([self objectForKey:kFLEXDefaultsToolbarTopMarginKey]) {
|
||||
return [self doubleForKey:kFLEXDefaultsToolbarTopMarginKey];
|
||||
@@ -52,6 +61,37 @@ NSString * const kFLEXDefaultsNetworkHostBlacklistKey = @"com.flipboard.FLEX.net
|
||||
[self setDouble:margin forKey:kFLEXDefaultsToolbarTopMarginKey];
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)flex_networkHostBlacklist {
|
||||
return [NSArray arrayWithContentsOfFile:[
|
||||
self flex_defaultsPathForFile:kFLEXDefaultsNetworkHostBlacklistKey
|
||||
]] ?: @[];
|
||||
}
|
||||
|
||||
- (void)setFlex_networkHostBlacklist:(NSArray<NSString *> *)blacklist {
|
||||
NSParameterAssert(blacklist);
|
||||
[blacklist writeToFile:[
|
||||
self flex_defaultsPathForFile:kFLEXDefaultsNetworkHostBlacklistKey
|
||||
] atomically:YES];
|
||||
}
|
||||
|
||||
- (BOOL)flex_registerDictionaryJSONViewerOnLaunch {
|
||||
return [self boolForKey:kFLEXDefaultsRegisterJSONExplorerKey];
|
||||
}
|
||||
|
||||
- (void)setFlex_registerDictionaryJSONViewerOnLaunch:(BOOL)enable {
|
||||
[self setBool:enable forKey:kFLEXDefaultsRegisterJSONExplorerKey];
|
||||
}
|
||||
|
||||
#pragma mark System Log
|
||||
|
||||
- (BOOL)flex_disableOSLog {
|
||||
return [self boolForKey:kFLEXDefaultsDisableOSLogForceASLKey];
|
||||
}
|
||||
|
||||
- (void)setFlex_disableOSLog:(BOOL)disable {
|
||||
[self setBool:disable forKey:kFLEXDefaultsDisableOSLogForceASLKey];
|
||||
}
|
||||
|
||||
- (BOOL)flex_cacheOSLogMessages {
|
||||
return [self boolForKey:kFLEXDefaultsiOSPersistentOSLogKey];
|
||||
}
|
||||
@@ -64,6 +104,8 @@ NSString * const kFLEXDefaultsNetworkHostBlacklistKey = @"com.flipboard.FLEX.net
|
||||
];
|
||||
}
|
||||
|
||||
#pragma mark Object Explorer
|
||||
|
||||
- (BOOL)flex_explorerHidesPropertyIvars {
|
||||
return [self boolForKey:kFLEXDefaultsHidePropertyIvarsKey];
|
||||
}
|
||||
@@ -100,17 +142,16 @@ NSString * const kFLEXDefaultsNetworkHostBlacklistKey = @"com.flipboard.FLEX.net
|
||||
];
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)flex_networkHostBlacklist {
|
||||
return [NSArray arrayWithContentsOfFile:[
|
||||
self flex_defaultsPathForFile:kFLEXDefaultsNetworkHostBlacklistKey
|
||||
]] ?: @[];
|
||||
- (BOOL)flex_explorerHidesVariablePreviews {
|
||||
return [self boolForKey:kFLEXDefaultsHideVariablePreviewsKey];
|
||||
}
|
||||
|
||||
- (void)setFlex_networkHostBlacklist:(NSArray<NSString *> *)blacklist {
|
||||
NSParameterAssert(blacklist);
|
||||
[blacklist writeToFile:[
|
||||
self flex_defaultsPathForFile:kFLEXDefaultsNetworkHostBlacklistKey
|
||||
] atomically:YES];
|
||||
- (void)setFlex_explorerHidesVariablePreviews:(BOOL)hide {
|
||||
[self setBool:hide forKey:kFLEXDefaultsHideVariablePreviewsKey];
|
||||
[NSNotificationCenter.defaultCenter
|
||||
postNotificationName:kFLEXDefaultsHideVariablePreviewsKey
|
||||
object:nil
|
||||
];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -29,7 +29,9 @@ typedef FLEXAlertAction *(^FLEXAlertActionHandler)(void(^handler)(NSArray<NSStri
|
||||
/// Construct and display an alert
|
||||
+ (void)makeAlert:(FLEXAlertBuilder)block showFrom:(UIViewController *)viewController;
|
||||
/// Construct and display an action sheet-style alert
|
||||
+ (void)makeSheet:(FLEXAlertBuilder)block showFrom:(UIViewController *)viewController;
|
||||
+ (void)makeSheet:(FLEXAlertBuilder)block
|
||||
showFrom:(UIViewController *)viewController
|
||||
source:(id)viewOrBarItem;
|
||||
|
||||
/// Construct an alert
|
||||
+ (UIAlertController *)makeAlert:(FLEXAlertBuilder)block;
|
||||
|
||||
@@ -62,17 +62,42 @@ NSAssert(!self._action, @"Cannot mutate action after retreiving underlying UIAle
|
||||
return alert._controller;
|
||||
}
|
||||
|
||||
+ (void)make:(FLEXAlertBuilder)block withStyle:(UIAlertControllerStyle)style showFrom:(UIViewController *)viewController {
|
||||
+ (void)make:(FLEXAlertBuilder)block
|
||||
withStyle:(UIAlertControllerStyle)style
|
||||
showFrom:(UIViewController *)viewController
|
||||
source:(id)viewOrBarItem {
|
||||
UIAlertController *alert = [self make:block withStyle:style];
|
||||
if ([viewOrBarItem isKindOfClass:[UIBarButtonItem class]]) {
|
||||
alert.popoverPresentationController.barButtonItem = viewOrBarItem;
|
||||
} else if ([viewOrBarItem isKindOfClass:[UIView class]]) {
|
||||
alert.popoverPresentationController.sourceView = viewOrBarItem;
|
||||
alert.popoverPresentationController.sourceRect = [viewOrBarItem bounds];
|
||||
} else if (viewOrBarItem) {
|
||||
NSParameterAssert(
|
||||
[viewOrBarItem isKindOfClass:[UIBarButtonItem class]] ||
|
||||
[viewOrBarItem isKindOfClass:[UIView class]] ||
|
||||
!viewOrBarItem
|
||||
);
|
||||
}
|
||||
[viewController presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
+ (void)makeAlert:(FLEXAlertBuilder)block showFrom:(UIViewController *)viewController {
|
||||
[self make:block withStyle:UIAlertControllerStyleAlert showFrom:viewController];
|
||||
+ (void)makeAlert:(FLEXAlertBuilder)block showFrom:(UIViewController *)controller {
|
||||
[self make:block withStyle:UIAlertControllerStyleAlert showFrom:controller source:nil];
|
||||
}
|
||||
|
||||
+ (void)makeSheet:(FLEXAlertBuilder)block showFrom:(UIViewController *)viewController {
|
||||
[self make:block withStyle:UIAlertControllerStyleActionSheet showFrom:viewController];
|
||||
+ (void)makeSheet:(FLEXAlertBuilder)block showFrom:(UIViewController *)controller {
|
||||
[self make:block withStyle:UIAlertControllerStyleActionSheet showFrom:controller source:nil];
|
||||
}
|
||||
|
||||
/// Construct and display an action sheet-style alert
|
||||
+ (void)makeSheet:(FLEXAlertBuilder)block
|
||||
showFrom:(UIViewController *)controller
|
||||
source:(id)viewOrBarItem {
|
||||
[self make:block
|
||||
withStyle:UIAlertControllerStyleActionSheet
|
||||
showFrom:controller
|
||||
source:viewOrBarItem];
|
||||
}
|
||||
|
||||
+ (UIAlertController *)makeAlert:(FLEXAlertBuilder)block {
|
||||
|
||||
@@ -71,4 +71,8 @@ NS_INLINE CGRect FLEXRectSetHeight(CGRect r, CGFloat height) {
|
||||
stringWithFormat:(count == 1 ? singularFormat : pluralFormat), @(count) \
|
||||
]
|
||||
|
||||
#define flex_dispatch_after(nSeconds, onQueue, block) \
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, \
|
||||
(int64_t)(nSeconds * NSEC_PER_SEC)), onQueue, block)
|
||||
|
||||
#endif /* FLEXMacros_h */
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#import <objc/runtime.h>
|
||||
#import "FLEXTypeEncodingParser.h"
|
||||
#import "FLEXAlert.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "UIFont+FLEX.h"
|
||||
#import "NSMapTable+FLEX_Subscripting.h"
|
||||
#import "FLEXMacros.h"
|
||||
|
||||
@@ -34,21 +34,23 @@ typedef struct FLEXTypeInfo {
|
||||
/// so we need to track whenever a type contains a union
|
||||
/// so that we can clean it out of pointer types.
|
||||
BOOL containsUnion;
|
||||
/// size can only be 0 if not void
|
||||
BOOL isVoid;
|
||||
} FLEXTypeInfo;
|
||||
|
||||
/// Type info for a completely unsupported type.
|
||||
static FLEXTypeInfo FLEXTypeInfoUnsupported = (FLEXTypeInfo){ -1, 0, NO, NO, NO };
|
||||
static FLEXTypeInfo FLEXTypeInfoUnsupported = (FLEXTypeInfo){ -1, 0, NO, NO, NO, NO };
|
||||
/// Type info for the void return type.
|
||||
static FLEXTypeInfo FLEXTypeInfoVoid = (FLEXTypeInfo){ 0, 0, YES, NO, NO };
|
||||
static FLEXTypeInfo FLEXTypeInfoVoid = (FLEXTypeInfo){ 0, 0, YES, NO, NO, YES };
|
||||
|
||||
/// Builds type info for a fully or partially supported type.
|
||||
static inline FLEXTypeInfo FLEXTypeInfoMake(ssize_t size, ssize_t align, BOOL fixed) {
|
||||
return (FLEXTypeInfo){ size, align, YES, fixed, NO };
|
||||
return (FLEXTypeInfo){ size, align, YES, fixed, NO, NO };
|
||||
}
|
||||
|
||||
/// Builds type info for a fully or partially supported type.
|
||||
static inline FLEXTypeInfo FLEXTypeInfoMakeU(ssize_t size, ssize_t align, BOOL fixed, BOOL hasUnion) {
|
||||
return (FLEXTypeInfo){ size, align, YES, fixed, hasUnion };
|
||||
return (FLEXTypeInfo){ size, align, YES, fixed, hasUnion, NO };
|
||||
}
|
||||
|
||||
BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *alignp) {
|
||||
@@ -119,7 +121,7 @@ BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *al
|
||||
while (!parser.scan.isAtEnd) {
|
||||
FLEXTypeInfo info = [parser parseNextType];
|
||||
|
||||
if (!info.supported || info.containsUnion || info.size == 0) {
|
||||
if (!info.supported || info.containsUnion || (info.size == 0 && !info.isVoid)) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
@property (nonatomic, readonly) NSUInteger size;
|
||||
/// Describes the type encoding, size, offset, and objc_ivar
|
||||
@property (nonatomic, readonly) NSString *details;
|
||||
/// The full path of the image that contains this ivar definition,
|
||||
/// or \c nil if this ivar was probably defined at runtime.
|
||||
@property (nonatomic, readonly) NSString *imagePath;
|
||||
|
||||
/// For internal use
|
||||
@property (nonatomic) id tag;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#import "FLEXRuntimeSafety.h"
|
||||
#import "FLEXTypeEncodingParser.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
@interface FLEXIvar () {
|
||||
NSString *_flex_description;
|
||||
@@ -82,6 +83,11 @@
|
||||
typeForDetails = @"no type info";
|
||||
sizeForDetails = @"unknown size";
|
||||
}
|
||||
|
||||
Dl_info exeInfo;
|
||||
if (dladdr(_objc_ivar, &exeInfo)) {
|
||||
_imagePath = exeInfo.dli_fname ? @(exeInfo.dli_fname) : nil;
|
||||
}
|
||||
|
||||
_details = [NSString stringWithFormat:
|
||||
@"%@, offset %@ — %@",
|
||||
|
||||
@@ -59,6 +59,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, readonly) FLEXTypeEncoding *returnType;
|
||||
/// The return size of the method.
|
||||
@property (nonatomic, readonly) NSUInteger returnSize;
|
||||
/// The full path of the image that contains this method definition,
|
||||
/// or \c nil if this ivar was probably defined at runtime.
|
||||
@property (nonatomic, readonly) NSString *imagePath;
|
||||
|
||||
/// Like @code - (void)foo:(int)bar @endcode
|
||||
@property (nonatomic, readonly) NSString *description;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#import "FLEXMirror.h"
|
||||
#import "FLEXTypeEncodingParser.h"
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
@implementation FLEXMethod
|
||||
@dynamic implementation;
|
||||
@@ -153,8 +154,13 @@
|
||||
_selector = method_getName(_objc_method);
|
||||
_numberOfArguments = method_getNumberOfArguments(_objc_method);
|
||||
_name = NSStringFromSelector(_selector);
|
||||
_returnType = (FLEXTypeEncoding *)_signature.methodReturnType;
|
||||
_returnType = (FLEXTypeEncoding *)_signature.methodReturnType ?: "";
|
||||
_returnSize = _signature.methodReturnLength;
|
||||
|
||||
Dl_info exeInfo;
|
||||
if (dladdr(_objc_method, &exeInfo)) {
|
||||
_imagePath = exeInfo.dli_fname ? @(exeInfo.dli_fname) : nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Public
|
||||
|
||||
@@ -59,8 +59,12 @@
|
||||
@property (nonatomic, readonly) BOOL multiple;
|
||||
/// @return The bundle of the image that contains this property definition,
|
||||
/// or \c nil if this property was not created with \c property:onClass or
|
||||
/// if this property is probably defined in the objc runtime.
|
||||
/// if this property was probably defined at runtime.
|
||||
@property (nonatomic, readonly) NSString *imageName;
|
||||
/// The full path of the image that contains this property definition,
|
||||
/// or \c nil if this property was not created with \c property:onClass or
|
||||
/// if this property was probably defined at runtime.
|
||||
@property (nonatomic, readonly) NSString *imagePath;
|
||||
|
||||
/// For internal use
|
||||
@property (nonatomic) id tag;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
@implementation FLEXProperty
|
||||
@synthesize multiple = _multiple;
|
||||
@synthesize imageName = _imageName;
|
||||
@synthesize imagePath = _imagePath;
|
||||
|
||||
#pragma mark Initializers
|
||||
|
||||
@@ -88,7 +89,9 @@
|
||||
#pragma mark Private
|
||||
|
||||
- (void)examine {
|
||||
_type = (FLEXTypeEncoding)[self.attributes.typeEncoding characterAtIndex:0];
|
||||
if (self.attributes.typeEncoding.length) {
|
||||
_type = (FLEXTypeEncoding)[self.attributes.typeEncoding characterAtIndex:0];
|
||||
}
|
||||
|
||||
// Return the given selector if the class responds to it
|
||||
Class cls = _cls;
|
||||
@@ -153,13 +156,16 @@
|
||||
}
|
||||
|
||||
- (void)computeSymbolInfo:(BOOL)forceBundle {
|
||||
Dl_info exeInfo;
|
||||
if (dladdr(_objc_property, &exeInfo)) {
|
||||
_imagePath = exeInfo.dli_fname ? @(exeInfo.dli_fname) : nil;
|
||||
}
|
||||
|
||||
if ((!_multiple || !_uniqueCheckFlag) && _cls) {
|
||||
_multiple = _objc_property != class_getProperty(_cls, self.name.UTF8String);
|
||||
|
||||
if (_multiple || forceBundle) {
|
||||
Dl_info exeInfo;
|
||||
dladdr(_objc_property, &exeInfo);
|
||||
NSString *path = @(exeInfo.dli_fname).stringByDeletingLastPathComponent;
|
||||
NSString *path = _imagePath.stringByDeletingLastPathComponent;
|
||||
_imageName = [NSBundle bundleWithPath:path].executablePath.lastPathComponent;
|
||||
}
|
||||
}
|
||||
@@ -170,6 +176,11 @@
|
||||
return _multiple;
|
||||
}
|
||||
|
||||
- (NSString *)imagePath {
|
||||
[self computeSymbolInfo:YES];
|
||||
return _imagePath;
|
||||
}
|
||||
|
||||
- (NSString *)imageName {
|
||||
[self computeSymbolInfo:YES];
|
||||
return _imageName;
|
||||
|
||||
@@ -60,6 +60,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, readonly, nullable) SEL customGetter;
|
||||
/// The property's custom setter, if any.
|
||||
@property (nonatomic, readonly, nullable) SEL customSetter;
|
||||
/// The property's custom getter as a string, if any.
|
||||
@property (nonatomic, readonly, nullable) NSString *customGetterString;
|
||||
/// The property's custom setter as a string, if any.
|
||||
@property (nonatomic, readonly, nullable) NSString *customSetterString;
|
||||
|
||||
@property (nonatomic, readonly) BOOL isReadOnly;
|
||||
@property (nonatomic, readonly) BOOL isCopy;
|
||||
|
||||
@@ -58,8 +58,10 @@
|
||||
_typeEncoding = attributes[kFLEXPropertyAttributeKeyTypeEncoding];
|
||||
_backingIvar = attributes[kFLEXPropertyAttributeKeyBackingIvarName];
|
||||
_oldTypeEncoding = attributes[kFLEXPropertyAttributeKeyOldStyleTypeEncoding];
|
||||
_customGetter = NSSelectorFromString(attributes[kFLEXPropertyAttributeKeyCustomGetter]);
|
||||
_customSetter = NSSelectorFromString(attributes[kFLEXPropertyAttributeKeyCustomSetter]);
|
||||
_customGetterString = attributes[kFLEXPropertyAttributeKeyCustomGetter];
|
||||
_customSetterString = attributes[kFLEXPropertyAttributeKeyCustomSetter];
|
||||
_customGetter = NSSelectorFromString(_customGetterString);
|
||||
_customSetter = NSSelectorFromString(_customSetterString);
|
||||
_isReadOnly = attributes[kFLEXPropertyAttributeKeyReadOnly] != nil;
|
||||
_isCopy = attributes[kFLEXPropertyAttributeKeyCopy] != nil;
|
||||
_isRetained = attributes[kFLEXPropertyAttributeKeyRetain] != nil;
|
||||
@@ -363,4 +365,12 @@ PropertyWithDeltaFlag(BOOL, isGarbageCollectable, IsGarbageCollectable);
|
||||
return _fullDeclaration;
|
||||
}
|
||||
|
||||
- (NSString *)customGetterString {
|
||||
return _customGetter ? NSStringFromSelector(_customGetter) : nil;
|
||||
}
|
||||
|
||||
- (NSString *)customSetterString {
|
||||
return _customSetter ? NSStringFromSelector(_customSetter) : nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,14 +22,23 @@
|
||||
|
||||
/// The name of the protocol.
|
||||
@property (nonatomic, readonly) NSString *name;
|
||||
/// The properties in the protocol, if any.
|
||||
@property (nonatomic, readonly) NSArray<FLEXProperty *> *properties;
|
||||
/// The required methods of the protocol, if any. This includes property getters and setters.
|
||||
@property (nonatomic, readonly) NSArray<FLEXMethodDescription *> *requiredMethods;
|
||||
/// The optional methods of the protocol, if any. This includes property getters and setters.
|
||||
@property (nonatomic, readonly) NSArray<FLEXMethodDescription *> *optionalMethods;
|
||||
/// All protocols that this protocol conforms to, if any.
|
||||
@property (nonatomic, readonly) NSArray<FLEXProtocol *> *protocols;
|
||||
/// The full path of the image that contains this protocol definition,
|
||||
/// or \c nil if this protocol was probably defined at runtime.
|
||||
@property (nonatomic, readonly) NSString *imagePath;
|
||||
|
||||
/// The properties in the protocol, if any. \c nil on iOS 10+
|
||||
@property (nonatomic, readonly) NSArray<FLEXProperty *> *properties API_DEPRECATED("Use the more specific accessors below", ios(2.0, 10.0));
|
||||
|
||||
/// The required properties in the protocol, if any.
|
||||
@property (nonatomic, readonly) NSArray<FLEXProperty *> *requiredProperties API_AVAILABLE(ios(10.0));
|
||||
/// The optional properties in the protocol, if any.
|
||||
@property (nonatomic, readonly) NSArray<FLEXProperty *> *optionalProperties API_AVAILABLE(ios(10.0));
|
||||
|
||||
/// For internal use
|
||||
@property (nonatomic) id tag;
|
||||
@@ -44,7 +53,8 @@
|
||||
#pragma mark Method descriptions
|
||||
@interface FLEXMethodDescription : NSObject
|
||||
|
||||
+ (instancetype)description:(struct objc_method_description)methodDescription;
|
||||
+ (instancetype)description:(struct objc_method_description)description;
|
||||
+ (instancetype)description:(struct objc_method_description)description instance:(BOOL)isInstance;
|
||||
|
||||
/// The underlying method description data structure.
|
||||
@property (nonatomic, readonly) struct objc_method_description objc_description;
|
||||
@@ -54,4 +64,6 @@
|
||||
@property (nonatomic, readonly) NSString *typeEncoding;
|
||||
/// The method's return type.
|
||||
@property (nonatomic, readonly) FLEXTypeEncoding returnType;
|
||||
/// \c @YES if this is an instance method, \c @NO if it is a class method, or \c nil if unspecified
|
||||
@property (nonatomic, readonly) NSNumber *instance;
|
||||
@end
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
#import "FLEXProtocol.h"
|
||||
#import "FLEXProperty.h"
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
|
||||
#import "NSArray+FLEX.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
@implementation FLEXProtocol
|
||||
|
||||
@@ -66,37 +67,101 @@
|
||||
|
||||
- (void)examine {
|
||||
_name = @(protocol_getName(self.objc_protocol));
|
||||
unsigned int prcount, pccount, mdrcount, mdocount;
|
||||
|
||||
objc_property_t *objcproperties = protocol_copyPropertyList(self.objc_protocol, &prcount);
|
||||
Protocol * __unsafe_unretained *objcprotocols = protocol_copyProtocolList(self.objc_protocol, &pccount);
|
||||
struct objc_method_description *objcrmethods = protocol_copyMethodDescriptionList(self.objc_protocol, YES, YES, &mdrcount);
|
||||
struct objc_method_description *objcomethods = protocol_copyMethodDescriptionList(self.objc_protocol, NO, YES, &mdocount);
|
||||
// imagePath
|
||||
Dl_info exeInfo;
|
||||
if (dladdr((__bridge const void *)(_objc_protocol), &exeInfo)) {
|
||||
_imagePath = exeInfo.dli_fname ? @(exeInfo.dli_fname) : nil;
|
||||
}
|
||||
|
||||
NSMutableArray *properties = [NSMutableArray new];
|
||||
for (int i = 0; i < prcount; i++)
|
||||
[properties addObject:[FLEXProperty property:objcproperties[i]]];
|
||||
_properties = properties;
|
||||
// Conformances and methods //
|
||||
|
||||
NSMutableArray *protocols = [NSMutableArray new];
|
||||
for (int i = 0; i < pccount; i++)
|
||||
[protocols addObject:[FLEXProtocol protocol:objcprotocols[i]]];
|
||||
_protocols = protocols;
|
||||
unsigned int pccount, mdrcount, mdocount;
|
||||
struct objc_method_description *objcrMethods, *objcoMethods;
|
||||
Protocol *protocol = _objc_protocol;
|
||||
Protocol * __unsafe_unretained *protocols = protocol_copyProtocolList(protocol, &pccount);
|
||||
|
||||
NSMutableArray *requiredMethods = [NSMutableArray new];
|
||||
for (int i = 0; i < mdrcount; i++)
|
||||
[requiredMethods addObject:[FLEXMethodDescription description:objcrmethods[i]]];
|
||||
_requiredMethods = requiredMethods;
|
||||
// Protocols
|
||||
_protocols = [NSArray flex_forEachUpTo:pccount map:^id(NSUInteger i) {
|
||||
return [FLEXProtocol protocol:protocols[i]];
|
||||
}];
|
||||
free(protocols);
|
||||
|
||||
NSMutableArray *optionalMethods = [NSMutableArray new];
|
||||
for (int i = 0; i < mdocount; i++)
|
||||
[optionalMethods addObject:[FLEXMethodDescription description:objcomethods[i]]];
|
||||
_optionalMethods = optionalMethods;
|
||||
// Required instance methods
|
||||
objcrMethods = protocol_copyMethodDescriptionList(protocol, YES, YES, &mdrcount);
|
||||
NSArray *rMethods = [NSArray flex_forEachUpTo:mdrcount map:^id(NSUInteger i) {
|
||||
return [FLEXMethodDescription description:objcrMethods[i] instance:YES];
|
||||
}];
|
||||
free(objcrMethods);
|
||||
|
||||
free(objcproperties);
|
||||
free(objcprotocols);
|
||||
free(objcrmethods);
|
||||
free(objcomethods);
|
||||
// Required class methods
|
||||
objcrMethods = protocol_copyMethodDescriptionList(protocol, YES, NO, &mdrcount);
|
||||
_requiredMethods = [[NSArray flex_forEachUpTo:mdrcount map:^id(NSUInteger i) {
|
||||
return [FLEXMethodDescription description:objcrMethods[i] instance:NO];
|
||||
}] arrayByAddingObjectsFromArray:rMethods];
|
||||
free(objcrMethods);
|
||||
|
||||
// Optional instance methods
|
||||
objcoMethods = protocol_copyMethodDescriptionList(protocol, NO, YES, &mdocount);
|
||||
NSArray *oMethods = [NSArray flex_forEachUpTo:mdocount map:^id(NSUInteger i) {
|
||||
return [FLEXMethodDescription description:objcoMethods[i] instance:YES];
|
||||
}];
|
||||
free(objcoMethods);
|
||||
|
||||
// Optional class methods
|
||||
objcoMethods = protocol_copyMethodDescriptionList(protocol, NO, NO, &mdocount);
|
||||
_optionalMethods = [[NSArray flex_forEachUpTo:mdocount map:^id(NSUInteger i) {
|
||||
return [FLEXMethodDescription description:objcoMethods[i] instance:NO];
|
||||
}] arrayByAddingObjectsFromArray:oMethods];
|
||||
free(objcoMethods);
|
||||
|
||||
// Properties is a hassle because they didn't fix the API until iOS 10 //
|
||||
|
||||
if (@available(iOS 10.0, *)) {
|
||||
unsigned int prrcount, procount;
|
||||
Class instance = [NSObject class], meta = objc_getMetaClass("NSObject");
|
||||
|
||||
// Required class and instance properties //
|
||||
|
||||
// Instance first
|
||||
objc_property_t *rProps = protocol_copyPropertyList2(protocol, &prrcount, YES, YES);
|
||||
NSArray *rProperties = [NSArray flex_forEachUpTo:prrcount map:^id(NSUInteger i) {
|
||||
return [FLEXProperty property:rProps[i] onClass:instance];
|
||||
}];
|
||||
free(rProps);
|
||||
|
||||
// Then class
|
||||
rProps = protocol_copyPropertyList2(protocol, &prrcount, NO, YES);
|
||||
_requiredProperties = [[NSArray flex_forEachUpTo:prrcount map:^id(NSUInteger i) {
|
||||
return [FLEXProperty property:rProps[i] onClass:instance];
|
||||
}] arrayByAddingObjectsFromArray:rProperties];
|
||||
free(rProps);
|
||||
|
||||
// Optional class and instance properties //
|
||||
|
||||
// Instance first
|
||||
objc_property_t *oProps = protocol_copyPropertyList2(protocol, &procount, YES, YES);
|
||||
NSArray *oProperties = [NSArray flex_forEachUpTo:prrcount map:^id(NSUInteger i) {
|
||||
return [FLEXProperty property:oProps[i] onClass:meta];
|
||||
}];
|
||||
free(oProps);
|
||||
|
||||
// Then class
|
||||
oProps = protocol_copyPropertyList2(protocol, &procount, NO, YES);
|
||||
_optionalProperties = [[NSArray flex_forEachUpTo:procount map:^id(NSUInteger i) {
|
||||
return [FLEXProperty property:oProps[i] onClass:meta];
|
||||
}] arrayByAddingObjectsFromArray:oProperties];
|
||||
free(oProps);
|
||||
|
||||
} else {
|
||||
unsigned int prcount;
|
||||
objc_property_t *objcproperties = protocol_copyPropertyList(protocol, &prcount);
|
||||
_properties = [NSArray flex_forEachUpTo:prcount map:^id(NSUInteger i) {
|
||||
return [FLEXProperty property:objcproperties[i]];
|
||||
}];
|
||||
|
||||
free(objcproperties);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)conformsTo:(Protocol *)protocol {
|
||||
@@ -117,11 +182,15 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (instancetype)description:(struct objc_method_description)methodDescription {
|
||||
return [[self alloc] initWithDescription:methodDescription];
|
||||
+ (instancetype)description:(struct objc_method_description)description {
|
||||
return [[self alloc] initWithDescription:description instance:nil];
|
||||
}
|
||||
|
||||
- (id)initWithDescription:(struct objc_method_description)md {
|
||||
+ (instancetype)description:(struct objc_method_description)description instance:(BOOL)isInstance {
|
||||
return [[self alloc] initWithDescription:description instance:@(isInstance)];
|
||||
}
|
||||
|
||||
- (id)initWithDescription:(struct objc_method_description)md instance:(NSNumber *)instance {
|
||||
NSParameterAssert(md.name != NULL);
|
||||
|
||||
self = [super init];
|
||||
@@ -130,6 +199,7 @@
|
||||
_selector = md.name;
|
||||
_typeEncoding = @(md.types);
|
||||
_returnType = (FLEXTypeEncoding)[self.typeEncoding characterAtIndex:0];
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -60,10 +60,10 @@ struct rebindings_entry {
|
||||
struct rebindings_entry *next;
|
||||
};
|
||||
|
||||
static struct rebindings_entry *_rebindings_head;
|
||||
static struct rebindings_entry *_flex_rebindings_head;
|
||||
|
||||
/// @return 0 on success
|
||||
static int prepend_rebindings(struct rebindings_entry **rebindings_head,
|
||||
static int flex_prepend_rebindings(struct rebindings_entry **rebindings_head,
|
||||
struct rebinding rebindings[],
|
||||
size_t nel) {
|
||||
struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry));
|
||||
@@ -85,7 +85,7 @@ static int prepend_rebindings(struct rebindings_entry **rebindings_head,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vm_prot_t get_protection(void *sectionStart) {
|
||||
static vm_prot_t flex_get_protection(void *sectionStart) {
|
||||
mach_port_t task = mach_task_self();
|
||||
vm_size_t size = 0;
|
||||
vm_address_t address = (vm_address_t)sectionStart;
|
||||
@@ -110,19 +110,19 @@ static vm_prot_t get_protection(void *sectionStart) {
|
||||
return VM_PROT_READ;
|
||||
}
|
||||
}
|
||||
static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
|
||||
section_t *section,
|
||||
intptr_t slide,
|
||||
nlist_t *symtab,
|
||||
char *strtab,
|
||||
uint32_t *indirect_symtab) {
|
||||
static void flex_perform_rebinding_with_section(struct rebindings_entry *rebindings,
|
||||
section_t *section,
|
||||
intptr_t slide,
|
||||
nlist_t *symtab,
|
||||
char *strtab,
|
||||
uint32_t *indirect_symtab) {
|
||||
const bool isDataConst = strcmp(section->segname, "__DATA_CONST") == 0;
|
||||
uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;
|
||||
void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);
|
||||
vm_prot_t oldProtection = VM_PROT_READ;
|
||||
|
||||
if (isDataConst) {
|
||||
oldProtection = get_protection(rebindings);
|
||||
oldProtection = flex_get_protection(rebindings);
|
||||
mprotect(indirect_symbol_bindings, section->size, PROT_READ | PROT_WRITE);
|
||||
}
|
||||
|
||||
@@ -177,9 +177,9 @@ static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
|
||||
}
|
||||
}
|
||||
|
||||
static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
|
||||
const struct mach_header *header,
|
||||
intptr_t slide) {
|
||||
static void flex_rebind_symbols_for_image(struct rebindings_entry *rebindings,
|
||||
const struct mach_header *header,
|
||||
intptr_t slide) {
|
||||
Dl_info info;
|
||||
if (dladdr(header, &info) == 0) {
|
||||
return;
|
||||
@@ -232,12 +232,12 @@ static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
|
||||
section_t *sect = (section_t *)(cur + sizeof(segment_command_t)) + j;
|
||||
|
||||
if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) {
|
||||
perform_rebinding_with_section(
|
||||
flex_perform_rebinding_with_section(
|
||||
rebindings, sect, slide, symtab, strtab, indirect_symtab
|
||||
);
|
||||
}
|
||||
if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) {
|
||||
perform_rebinding_with_section(
|
||||
flex_perform_rebinding_with_section(
|
||||
rebindings, sect, slide, symtab, strtab, indirect_symtab
|
||||
);
|
||||
}
|
||||
@@ -246,19 +246,19 @@ static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
|
||||
}
|
||||
}
|
||||
|
||||
static void _rebind_symbols_for_image(const struct mach_header *header,
|
||||
intptr_t slide) {
|
||||
rebind_symbols_for_image(_rebindings_head, header, slide);
|
||||
static void _flex_rebind_symbols_for_image(const struct mach_header *header,
|
||||
intptr_t slide) {
|
||||
flex_rebind_symbols_for_image(_flex_rebindings_head, header, slide);
|
||||
}
|
||||
|
||||
int rebind_symbols_image(void *header,
|
||||
intptr_t slide,
|
||||
struct rebinding rebindings[],
|
||||
size_t rebindings_nel) {
|
||||
int flex_rebind_symbols_image(void *header,
|
||||
intptr_t slide,
|
||||
struct rebinding rebindings[],
|
||||
size_t rebindings_nel) {
|
||||
struct rebindings_entry *rebindings_head = NULL;
|
||||
|
||||
int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);
|
||||
rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide);
|
||||
int retval = flex_prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);
|
||||
flex_rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide);
|
||||
|
||||
if (rebindings_head) {
|
||||
free(rebindings_head->rebindings);
|
||||
@@ -269,20 +269,20 @@ int rebind_symbols_image(void *header,
|
||||
}
|
||||
|
||||
/// @return 0 on success
|
||||
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {
|
||||
int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel);
|
||||
int flex_rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {
|
||||
int retval = flex_prepend_rebindings(&_flex_rebindings_head, rebindings, rebindings_nel);
|
||||
if (retval < 0) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
// If this was the first call, register callback for image additions (which is also invoked for
|
||||
// existing images, otherwise, just run on existing images
|
||||
if (!_rebindings_head->next) {
|
||||
_dyld_register_func_for_add_image(_rebind_symbols_for_image);
|
||||
if (!_flex_rebindings_head->next) {
|
||||
_dyld_register_func_for_add_image(_flex_rebind_symbols_for_image);
|
||||
} else {
|
||||
uint32_t c = _dyld_image_count();
|
||||
for (uint32_t i = 0; i < c; i++) {
|
||||
_rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));
|
||||
_flex_rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ struct rebinding {
|
||||
* @return 0 on success
|
||||
*/
|
||||
FISHHOOK_VISIBILITY
|
||||
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
|
||||
int flex_rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
|
||||
|
||||
/**
|
||||
* Rebinds as above, but only in the specified image. The header should point
|
||||
@@ -65,10 +65,10 @@ int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
|
||||
* @return 0 on success
|
||||
*/
|
||||
FISHHOOK_VISIBILITY
|
||||
int rebind_symbols_image(void *header,
|
||||
intptr_t slide,
|
||||
struct rebinding rebindings[],
|
||||
size_t rebindings_nel);
|
||||
int flex_rebind_symbols_image(void *header,
|
||||
intptr_t slide,
|
||||
struct rebinding rebindings[],
|
||||
size_t rebindings_nel);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#import "FHSView.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
|
||||
@interface FHSView (Snapshotting)
|
||||
+ (UIImage *)_snapshotView:(UIView *)view;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#import "FLEXAlert.h"
|
||||
#import "FLEXWindow.h"
|
||||
#import "FLEXResources.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "UIBarButtonItem+FLEX.h"
|
||||
|
||||
BOOL const kFHSViewControllerExcludeFLEXWindows = YES;
|
||||
@@ -162,7 +162,7 @@ BOOL const kFHSViewControllerExcludeFLEXWindows = YES;
|
||||
UIBarButtonItem.flex_flexibleSpace,
|
||||
[UIBarButtonItem
|
||||
itemWithImage:FLEXResources.moreIcon
|
||||
target:self action:@selector(didPressOptionsButton)
|
||||
target:self action:@selector(didPressOptionsButton:)
|
||||
],
|
||||
UIBarButtonItem.flex_flexibleSpace,
|
||||
[UIBarButtonItem itemWithCustomView:snapshotView.depthSlider]
|
||||
@@ -205,7 +205,7 @@ BOOL const kFHSViewControllerExcludeFLEXWindows = YES;
|
||||
|
||||
#pragma mark Events
|
||||
|
||||
- (void)didPressOptionsButton {
|
||||
- (void)didPressOptionsButton:(UIBarButtonItem *)sender {
|
||||
[FLEXAlert makeSheet:^(FLEXAlert *make) {
|
||||
if (self.selectedView) {
|
||||
make.button(@"Hide selected view").handler(^(NSArray<NSString *> *strings) {
|
||||
@@ -227,7 +227,7 @@ BOOL const kFHSViewControllerExcludeFLEXWindows = YES;
|
||||
[self.snapshotView toggleShowBorders];
|
||||
});
|
||||
make.button(@"Cancel").cancelStyle();
|
||||
} showFrom:self];
|
||||
} showFrom:self source:sender];
|
||||
}
|
||||
|
||||
- (void)resizeToolbarItems:(CGSize)viewSize {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#import "FHSViewSnapshot.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
|
||||
@implementation FHSViewSnapshot
|
||||
|
||||
|
||||
@@ -426,7 +426,7 @@
|
||||
DEVELOPMENT_TEAM = S6N2F22V2Z;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = "FLEXample/Supporting Files/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -451,7 +451,7 @@
|
||||
DEVELOPMENT_TEAM = S6N2F22V2Z;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = "FLEXample/Supporting Files/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
||||
@@ -40,7 +40,10 @@
|
||||
self.commits.list = [Commit commitsFrom:data];
|
||||
[self fadeInNewRows];
|
||||
} else {
|
||||
[FLEXAlert showAlert:@"Error" message:error.localizedDescription from:self];
|
||||
[FLEXAlert showAlert:@"Error"
|
||||
message:error.localizedDescription ?: @(statusCode).stringValue
|
||||
from:self
|
||||
];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import UIKit
|
||||
@UIApplicationMain @objcMembers
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var repeatingLogExampleTimer: Timer!
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions options: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
@@ -29,9 +30,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
// To show off the network logger, send several misc network requests
|
||||
MiscNetworkRequests.sendExampleRequests()
|
||||
|
||||
// For < iOS 13, set up the window here
|
||||
if ProcessInfo.processInfo.operatingSystemVersion.majorVersion < 13 {
|
||||
let window = UIWindow(frame: UIScreen.main.bounds)
|
||||
window.rootViewController = FLEXNavigationController(
|
||||
rootViewController: CommitListViewController()
|
||||
)
|
||||
self.window = window
|
||||
window.makeKeyAndVisible()
|
||||
FLEXManager.shared.showExplorer()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
func application(_ application: UIApplication,
|
||||
configurationForConnecting session: UISceneSession,
|
||||
options: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
@objcMembers
|
||||
@objcMembers @available(iOS 13.0, *)
|
||||
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>NSPhotoLibraryAddUsageDescription</string>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "FLEX"
|
||||
spec.version = "4.0.0"
|
||||
spec.version = "4.1.1"
|
||||
spec.summary = "A set of in-app debugging and exploration tools for iOS"
|
||||
spec.description = <<-DESC
|
||||
- Inspect and modify views in the hierarchy.
|
||||
|
||||
@@ -72,14 +72,14 @@
|
||||
3A4C95101B5B21410088C3F2 /* FLEXMethodCallingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C948B1B5B21410088C3F2 /* FLEXMethodCallingViewController.m */; };
|
||||
3A4C95221B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C949F1B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C95231B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94A01B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.m */; };
|
||||
3A4C95241B5B21410088C3F2 /* FLEXFileBrowserTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A11B5B21410088C3F2 /* FLEXFileBrowserTableViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C95251B5B21410088C3F2 /* FLEXFileBrowserTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94A21B5B21410088C3F2 /* FLEXFileBrowserTableViewController.m */; };
|
||||
3A4C95241B5B21410088C3F2 /* FLEXFileBrowserController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A11B5B21410088C3F2 /* FLEXFileBrowserController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C95251B5B21410088C3F2 /* FLEXFileBrowserController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94A21B5B21410088C3F2 /* FLEXFileBrowserController.m */; };
|
||||
3A4C95261B5B21410088C3F2 /* FLEXGlobalsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A31B5B21410088C3F2 /* FLEXGlobalsViewController.h */; };
|
||||
3A4C95271B5B21410088C3F2 /* FLEXGlobalsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94A41B5B21410088C3F2 /* FLEXGlobalsViewController.m */; };
|
||||
3A4C95281B5B21410088C3F2 /* FLEXObjectListViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A51B5B21410088C3F2 /* FLEXObjectListViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C95291B5B21410088C3F2 /* FLEXObjectListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94A61B5B21410088C3F2 /* FLEXObjectListViewController.m */; };
|
||||
3A4C952C1B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A91B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C952D1B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94AA1B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.m */; };
|
||||
3A4C952C1B5B21410088C3F2 /* FLEXLiveObjectsController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A91B5B21410088C3F2 /* FLEXLiveObjectsController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C952D1B5B21410088C3F2 /* FLEXLiveObjectsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94AA1B5B21410088C3F2 /* FLEXLiveObjectsController.m */; };
|
||||
3A4C952E1B5B21410088C3F2 /* FLEXWebViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94AB1B5B21410088C3F2 /* FLEXWebViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C952F1B5B21410088C3F2 /* FLEXWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94AC1B5B21410088C3F2 /* FLEXWebViewController.m */; };
|
||||
3A4C95301B5B21410088C3F2 /* FLEXSystemLogMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94AE1B5B21410088C3F2 /* FLEXSystemLogMessage.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
@@ -95,20 +95,20 @@
|
||||
3A4C953B1B5B21410088C3F2 /* FLEXNetworkSettingsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94BA1B5B21410088C3F2 /* FLEXNetworkSettingsController.m */; };
|
||||
3A4C953C1B5B21410088C3F2 /* FLEXNetworkTransaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94BB1B5B21410088C3F2 /* FLEXNetworkTransaction.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C953D1B5B21410088C3F2 /* FLEXNetworkTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94BC1B5B21410088C3F2 /* FLEXNetworkTransaction.m */; };
|
||||
3A4C953E1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94BD1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C953F1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94BE1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.m */; };
|
||||
3A4C95401B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94BF1B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C95411B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94C01B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.m */; };
|
||||
3A4C953E1B5B21410088C3F2 /* FLEXNetworkTransactionDetailController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94BD1B5B21410088C3F2 /* FLEXNetworkTransactionDetailController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C953F1B5B21410088C3F2 /* FLEXNetworkTransactionDetailController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94BE1B5B21410088C3F2 /* FLEXNetworkTransactionDetailController.m */; };
|
||||
3A4C95401B5B21410088C3F2 /* FLEXNetworkTransactionCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94BF1B5B21410088C3F2 /* FLEXNetworkTransactionCell.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C95411B5B21410088C3F2 /* FLEXNetworkTransactionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94C01B5B21410088C3F2 /* FLEXNetworkTransactionCell.m */; };
|
||||
3A4C95421B5B21410088C3F2 /* FLEXNetworkObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94C21B5B21410088C3F2 /* FLEXNetworkObserver.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3A4C95431B5B21410088C3F2 /* FLEXNetworkObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94C31B5B21410088C3F2 /* FLEXNetworkObserver.m */; };
|
||||
3A4C95471B5B217D0088C3F2 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4C95461B5B217D0088C3F2 /* libz.dylib */; };
|
||||
679F64861BD53B7B00A8C94C /* FLEXCookiesTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 679F64841BD53B7B00A8C94C /* FLEXCookiesTableViewController.h */; };
|
||||
679F64871BD53B7B00A8C94C /* FLEXCookiesTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 679F64851BD53B7B00A8C94C /* FLEXCookiesTableViewController.m */; };
|
||||
679F64861BD53B7B00A8C94C /* FLEXCookiesViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 679F64841BD53B7B00A8C94C /* FLEXCookiesViewController.h */; };
|
||||
679F64871BD53B7B00A8C94C /* FLEXCookiesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 679F64851BD53B7B00A8C94C /* FLEXCookiesViewController.m */; };
|
||||
71E1C2132307FBB800F5032A /* FLEXKeychain.h in Headers */ = {isa = PBXBuildFile; fileRef = 71E1C20B2307FBB700F5032A /* FLEXKeychain.h */; };
|
||||
71E1C2142307FBB800F5032A /* FLEXKeychainTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 71E1C20C2307FBB700F5032A /* FLEXKeychainTableViewController.h */; };
|
||||
71E1C2142307FBB800F5032A /* FLEXKeychainViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 71E1C20C2307FBB700F5032A /* FLEXKeychainViewController.h */; };
|
||||
71E1C2152307FBB800F5032A /* FLEXKeychainQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = 71E1C20D2307FBB700F5032A /* FLEXKeychainQuery.h */; };
|
||||
71E1C2172307FBB800F5032A /* FLEXKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 71E1C20F2307FBB700F5032A /* FLEXKeychain.m */; };
|
||||
71E1C2182307FBB800F5032A /* FLEXKeychainTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 71E1C2102307FBB700F5032A /* FLEXKeychainTableViewController.m */; };
|
||||
71E1C2182307FBB800F5032A /* FLEXKeychainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 71E1C2102307FBB700F5032A /* FLEXKeychainViewController.m */; };
|
||||
71E1C2192307FBB800F5032A /* FLEXKeychainQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 71E1C2112307FBB700F5032A /* FLEXKeychainQuery.m */; };
|
||||
7349FD6A22B93CDF00051810 /* FLEXColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 7349FD6822B93CDF00051810 /* FLEXColor.h */; };
|
||||
7349FD6B22B93CDF00051810 /* FLEXColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 7349FD6922B93CDF00051810 /* FLEXColor.m */; };
|
||||
@@ -226,8 +226,8 @@
|
||||
C383C3BA23B6A62A007A321B /* FLEXRuntimeSafety.m in Sources */ = {isa = PBXBuildFile; fileRef = C383C3B823B6A62A007A321B /* FLEXRuntimeSafety.m */; };
|
||||
C383C3BD23B6B398007A321B /* UITextField+Range.m in Sources */ = {isa = PBXBuildFile; fileRef = C383C3BB23B6B398007A321B /* UITextField+Range.m */; };
|
||||
C383C3BE23B6B398007A321B /* UITextField+Range.h in Headers */ = {isa = PBXBuildFile; fileRef = C383C3BC23B6B398007A321B /* UITextField+Range.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C383C3C123B6B429007A321B /* NSTimer+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = C383C3BF23B6B429007A321B /* NSTimer+Blocks.m */; };
|
||||
C383C3C223B6B429007A321B /* NSTimer+Blocks.h in Headers */ = {isa = PBXBuildFile; fileRef = C383C3C023B6B429007A321B /* NSTimer+Blocks.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C383C3C123B6B429007A321B /* NSTimer+FLEX.m in Sources */ = {isa = PBXBuildFile; fileRef = C383C3BF23B6B429007A321B /* NSTimer+FLEX.m */; };
|
||||
C383C3C223B6B429007A321B /* NSTimer+FLEX.h in Headers */ = {isa = PBXBuildFile; fileRef = C383C3C023B6B429007A321B /* NSTimer+FLEX.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C383C3C523B6BB81007A321B /* FLEXCodeFontCell.h in Headers */ = {isa = PBXBuildFile; fileRef = C383C3C323B6BB81007A321B /* FLEXCodeFontCell.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C383C3C623B6BB81007A321B /* FLEXCodeFontCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C383C3C423B6BB81007A321B /* FLEXCodeFontCell.m */; };
|
||||
C3854DF023F36C1700FCD1E2 /* FLEXTypeEncodingParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C3854DEF23F36C1700FCD1E2 /* FLEXTypeEncodingParserTests.m */; };
|
||||
@@ -304,8 +304,8 @@
|
||||
C3A9424A23C78878006871A3 /* FLEXHierarchyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C3A9424823C78878006871A3 /* FLEXHierarchyViewController.m */; };
|
||||
C3A9424D23C78CFF006871A3 /* FHSViewSnapshot.h in Headers */ = {isa = PBXBuildFile; fileRef = C3A9424B23C78CFF006871A3 /* FHSViewSnapshot.h */; };
|
||||
C3A9424E23C78CFF006871A3 /* FHSViewSnapshot.m in Sources */ = {isa = PBXBuildFile; fileRef = C3A9424C23C78CFF006871A3 /* FHSViewSnapshot.m */; };
|
||||
C3BFD070233C23ED0015FB82 /* NSArray+Functional.h in Headers */ = {isa = PBXBuildFile; fileRef = C3BFD06E233C23ED0015FB82 /* NSArray+Functional.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3BFD071233C23ED0015FB82 /* NSArray+Functional.m in Sources */ = {isa = PBXBuildFile; fileRef = C3BFD06F233C23ED0015FB82 /* NSArray+Functional.m */; };
|
||||
C3BFD070233C23ED0015FB82 /* NSArray+FLEX.h in Headers */ = {isa = PBXBuildFile; fileRef = C3BFD06E233C23ED0015FB82 /* NSArray+FLEX.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3BFD071233C23ED0015FB82 /* NSArray+FLEX.m in Sources */ = {isa = PBXBuildFile; fileRef = C3BFD06F233C23ED0015FB82 /* NSArray+FLEX.m */; };
|
||||
C3DB9F642107FC9600B46809 /* FLEXObjectRef.h in Headers */ = {isa = PBXBuildFile; fileRef = C3DB9F622107FC9600B46809 /* FLEXObjectRef.h */; };
|
||||
C3DB9F652107FC9600B46809 /* FLEXObjectRef.m in Sources */ = {isa = PBXBuildFile; fileRef = C3DB9F632107FC9600B46809 /* FLEXObjectRef.m */; };
|
||||
C3DC287C223ED5F200F48AA6 /* FLEXOSLogController.m in Sources */ = {isa = PBXBuildFile; fileRef = C34EE30721CB23CC00BD3A7C /* FLEXOSLogController.m */; };
|
||||
@@ -318,6 +318,8 @@
|
||||
C3E5D9FD2316E83700E655DB /* FLEXRuntime+Compare.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E5D9FB2316E83700E655DB /* FLEXRuntime+Compare.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3E5D9FE2316E83700E655DB /* FLEXRuntime+Compare.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E5D9FC2316E83700E655DB /* FLEXRuntime+Compare.m */; };
|
||||
C3E5DA02231700EE00E655DB /* FLEXObjectInfoSection.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E5DA00231700EE00E655DB /* FLEXObjectInfoSection.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3EB6F8D242E9C83006EA386 /* FLEXRuntimeExporter.m in Sources */ = {isa = PBXBuildFile; fileRef = C3EB6F8B242E9C83006EA386 /* FLEXRuntimeExporter.m */; };
|
||||
C3EB6F8E242E9C83006EA386 /* FLEXRuntimeExporter.h in Headers */ = {isa = PBXBuildFile; fileRef = C3EB6F8C242E9C83006EA386 /* FLEXRuntimeExporter.h */; };
|
||||
C3EE76BF22DFC63600EC0AA0 /* FLEXScopeCarousel.h in Headers */ = {isa = PBXBuildFile; fileRef = C3EE76BD22DFC63600EC0AA0 /* FLEXScopeCarousel.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3EE76C022DFC63600EC0AA0 /* FLEXScopeCarousel.m in Sources */ = {isa = PBXBuildFile; fileRef = C3EE76BE22DFC63600EC0AA0 /* FLEXScopeCarousel.m */; };
|
||||
C3F31D3D2267D883003C991A /* FLEXSubtitleTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = C3F31D342267D883003C991A /* FLEXSubtitleTableViewCell.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@@ -342,8 +344,8 @@
|
||||
C3F977842311B38F0032776D /* NSDictionary+ObjcRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = C3F9777E2311B38E0032776D /* NSDictionary+ObjcRuntime.m */; };
|
||||
C3F977852311B38F0032776D /* NSDictionary+ObjcRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = C3F9777F2311B38F0032776D /* NSDictionary+ObjcRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3F977862311B38F0032776D /* NSString+ObjcRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = C3F977802311B38F0032776D /* NSString+ObjcRuntime.m */; };
|
||||
C3F977872311B38F0032776D /* NSObject+Reflection.h in Headers */ = {isa = PBXBuildFile; fileRef = C3F977812311B38F0032776D /* NSObject+Reflection.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3F977882311B38F0032776D /* NSObject+Reflection.m in Sources */ = {isa = PBXBuildFile; fileRef = C3F977822311B38F0032776D /* NSObject+Reflection.m */; };
|
||||
C3F977872311B38F0032776D /* NSObject+FLEX_Reflection.h in Headers */ = {isa = PBXBuildFile; fileRef = C3F977812311B38F0032776D /* NSObject+FLEX_Reflection.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3F977882311B38F0032776D /* NSObject+FLEX_Reflection.m in Sources */ = {isa = PBXBuildFile; fileRef = C3F977822311B38F0032776D /* NSObject+FLEX_Reflection.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -427,14 +429,14 @@
|
||||
3A4C948B1B5B21410088C3F2 /* FLEXMethodCallingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXMethodCallingViewController.m; sourceTree = "<group>"; };
|
||||
3A4C949F1B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXFileBrowserSearchOperation.h; sourceTree = "<group>"; };
|
||||
3A4C94A01B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXFileBrowserSearchOperation.m; sourceTree = "<group>"; };
|
||||
3A4C94A11B5B21410088C3F2 /* FLEXFileBrowserTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXFileBrowserTableViewController.h; sourceTree = "<group>"; };
|
||||
3A4C94A21B5B21410088C3F2 /* FLEXFileBrowserTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXFileBrowserTableViewController.m; sourceTree = "<group>"; };
|
||||
3A4C94A11B5B21410088C3F2 /* FLEXFileBrowserController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXFileBrowserController.h; sourceTree = "<group>"; };
|
||||
3A4C94A21B5B21410088C3F2 /* FLEXFileBrowserController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXFileBrowserController.m; sourceTree = "<group>"; };
|
||||
3A4C94A31B5B21410088C3F2 /* FLEXGlobalsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXGlobalsViewController.h; sourceTree = "<group>"; };
|
||||
3A4C94A41B5B21410088C3F2 /* FLEXGlobalsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXGlobalsViewController.m; sourceTree = "<group>"; };
|
||||
3A4C94A51B5B21410088C3F2 /* FLEXObjectListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXObjectListViewController.h; sourceTree = "<group>"; };
|
||||
3A4C94A61B5B21410088C3F2 /* FLEXObjectListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXObjectListViewController.m; sourceTree = "<group>"; };
|
||||
3A4C94A91B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXLiveObjectsTableViewController.h; sourceTree = "<group>"; };
|
||||
3A4C94AA1B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXLiveObjectsTableViewController.m; sourceTree = "<group>"; };
|
||||
3A4C94A91B5B21410088C3F2 /* FLEXLiveObjectsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXLiveObjectsController.h; sourceTree = "<group>"; };
|
||||
3A4C94AA1B5B21410088C3F2 /* FLEXLiveObjectsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXLiveObjectsController.m; sourceTree = "<group>"; };
|
||||
3A4C94AB1B5B21410088C3F2 /* FLEXWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXWebViewController.h; sourceTree = "<group>"; };
|
||||
3A4C94AC1B5B21410088C3F2 /* FLEXWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXWebViewController.m; sourceTree = "<group>"; };
|
||||
3A4C94AE1B5B21410088C3F2 /* FLEXSystemLogMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXSystemLogMessage.h; sourceTree = "<group>"; };
|
||||
@@ -451,21 +453,21 @@
|
||||
3A4C94BA1B5B21410088C3F2 /* FLEXNetworkSettingsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXNetworkSettingsController.m; sourceTree = "<group>"; };
|
||||
3A4C94BB1B5B21410088C3F2 /* FLEXNetworkTransaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXNetworkTransaction.h; sourceTree = "<group>"; };
|
||||
3A4C94BC1B5B21410088C3F2 /* FLEXNetworkTransaction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXNetworkTransaction.m; sourceTree = "<group>"; };
|
||||
3A4C94BD1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXNetworkTransactionDetailTableViewController.h; sourceTree = "<group>"; };
|
||||
3A4C94BE1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXNetworkTransactionDetailTableViewController.m; sourceTree = "<group>"; };
|
||||
3A4C94BF1B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXNetworkTransactionTableViewCell.h; sourceTree = "<group>"; };
|
||||
3A4C94C01B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXNetworkTransactionTableViewCell.m; sourceTree = "<group>"; };
|
||||
3A4C94BD1B5B21410088C3F2 /* FLEXNetworkTransactionDetailController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXNetworkTransactionDetailController.h; sourceTree = "<group>"; };
|
||||
3A4C94BE1B5B21410088C3F2 /* FLEXNetworkTransactionDetailController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXNetworkTransactionDetailController.m; sourceTree = "<group>"; };
|
||||
3A4C94BF1B5B21410088C3F2 /* FLEXNetworkTransactionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXNetworkTransactionCell.h; sourceTree = "<group>"; };
|
||||
3A4C94C01B5B21410088C3F2 /* FLEXNetworkTransactionCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXNetworkTransactionCell.m; sourceTree = "<group>"; };
|
||||
3A4C94C21B5B21410088C3F2 /* FLEXNetworkObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXNetworkObserver.h; sourceTree = "<group>"; };
|
||||
3A4C94C31B5B21410088C3F2 /* FLEXNetworkObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXNetworkObserver.m; sourceTree = "<group>"; };
|
||||
3A4C94C41B5B21410088C3F2 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||
3A4C95461B5B217D0088C3F2 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||
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>"; };
|
||||
679F64841BD53B7B00A8C94C /* FLEXCookiesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXCookiesViewController.h; sourceTree = "<group>"; };
|
||||
679F64851BD53B7B00A8C94C /* FLEXCookiesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXCookiesViewController.m; sourceTree = "<group>"; };
|
||||
71E1C20B2307FBB700F5032A /* FLEXKeychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXKeychain.h; sourceTree = "<group>"; };
|
||||
71E1C20C2307FBB700F5032A /* FLEXKeychainTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXKeychainTableViewController.h; sourceTree = "<group>"; };
|
||||
71E1C20C2307FBB700F5032A /* FLEXKeychainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXKeychainViewController.h; sourceTree = "<group>"; };
|
||||
71E1C20D2307FBB700F5032A /* FLEXKeychainQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXKeychainQuery.h; sourceTree = "<group>"; };
|
||||
71E1C20F2307FBB700F5032A /* FLEXKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXKeychain.m; sourceTree = "<group>"; };
|
||||
71E1C2102307FBB700F5032A /* FLEXKeychainTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXKeychainTableViewController.m; sourceTree = "<group>"; };
|
||||
71E1C2102307FBB700F5032A /* FLEXKeychainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXKeychainViewController.m; sourceTree = "<group>"; };
|
||||
71E1C2112307FBB700F5032A /* FLEXKeychainQuery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXKeychainQuery.m; sourceTree = "<group>"; };
|
||||
7349FD6822B93CDF00051810 /* FLEXColor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXColor.h; sourceTree = "<group>"; };
|
||||
7349FD6922B93CDF00051810 /* FLEXColor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXColor.m; sourceTree = "<group>"; };
|
||||
@@ -585,8 +587,8 @@
|
||||
C383C3B823B6A62A007A321B /* FLEXRuntimeSafety.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXRuntimeSafety.m; sourceTree = "<group>"; };
|
||||
C383C3BB23B6B398007A321B /* UITextField+Range.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITextField+Range.m"; sourceTree = "<group>"; };
|
||||
C383C3BC23B6B398007A321B /* UITextField+Range.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITextField+Range.h"; sourceTree = "<group>"; };
|
||||
C383C3BF23B6B429007A321B /* NSTimer+Blocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+Blocks.m"; sourceTree = "<group>"; };
|
||||
C383C3C023B6B429007A321B /* NSTimer+Blocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+Blocks.h"; sourceTree = "<group>"; };
|
||||
C383C3BF23B6B429007A321B /* NSTimer+FLEX.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+FLEX.m"; sourceTree = "<group>"; };
|
||||
C383C3C023B6B429007A321B /* NSTimer+FLEX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+FLEX.h"; sourceTree = "<group>"; };
|
||||
C383C3C323B6BB81007A321B /* FLEXCodeFontCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXCodeFontCell.h; sourceTree = "<group>"; };
|
||||
C383C3C423B6BB81007A321B /* FLEXCodeFontCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXCodeFontCell.m; sourceTree = "<group>"; };
|
||||
C3854DEF23F36C1700FCD1E2 /* FLEXTypeEncodingParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXTypeEncodingParserTests.m; sourceTree = "<group>"; };
|
||||
@@ -659,8 +661,8 @@
|
||||
C3A9424823C78878006871A3 /* FLEXHierarchyViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXHierarchyViewController.m; sourceTree = "<group>"; };
|
||||
C3A9424B23C78CFF006871A3 /* FHSViewSnapshot.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FHSViewSnapshot.h; sourceTree = "<group>"; };
|
||||
C3A9424C23C78CFF006871A3 /* FHSViewSnapshot.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FHSViewSnapshot.m; sourceTree = "<group>"; };
|
||||
C3BFD06E233C23ED0015FB82 /* NSArray+Functional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSArray+Functional.h"; sourceTree = "<group>"; };
|
||||
C3BFD06F233C23ED0015FB82 /* NSArray+Functional.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Functional.m"; sourceTree = "<group>"; };
|
||||
C3BFD06E233C23ED0015FB82 /* NSArray+FLEX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSArray+FLEX.h"; sourceTree = "<group>"; };
|
||||
C3BFD06F233C23ED0015FB82 /* NSArray+FLEX.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSArray+FLEX.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>"; };
|
||||
C3DFCD922416BC6500BB7084 /* FLEXFilteringTableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXFilteringTableViewController.h; sourceTree = "<group>"; };
|
||||
@@ -672,6 +674,8 @@
|
||||
C3E5D9FB2316E83700E655DB /* FLEXRuntime+Compare.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FLEXRuntime+Compare.h"; sourceTree = "<group>"; };
|
||||
C3E5D9FC2316E83700E655DB /* FLEXRuntime+Compare.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "FLEXRuntime+Compare.m"; sourceTree = "<group>"; };
|
||||
C3E5DA00231700EE00E655DB /* FLEXObjectInfoSection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXObjectInfoSection.h; sourceTree = "<group>"; };
|
||||
C3EB6F8B242E9C83006EA386 /* FLEXRuntimeExporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXRuntimeExporter.m; sourceTree = "<group>"; };
|
||||
C3EB6F8C242E9C83006EA386 /* FLEXRuntimeExporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXRuntimeExporter.h; sourceTree = "<group>"; };
|
||||
C3EE76BD22DFC63600EC0AA0 /* FLEXScopeCarousel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXScopeCarousel.h; sourceTree = "<group>"; };
|
||||
C3EE76BE22DFC63600EC0AA0 /* FLEXScopeCarousel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXScopeCarousel.m; sourceTree = "<group>"; };
|
||||
C3F31D342267D883003C991A /* FLEXSubtitleTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXSubtitleTableViewCell.h; sourceTree = "<group>"; };
|
||||
@@ -698,8 +702,8 @@
|
||||
C3F9777E2311B38E0032776D /* NSDictionary+ObjcRuntime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+ObjcRuntime.m"; sourceTree = "<group>"; };
|
||||
C3F9777F2311B38F0032776D /* NSDictionary+ObjcRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+ObjcRuntime.h"; sourceTree = "<group>"; };
|
||||
C3F977802311B38F0032776D /* NSString+ObjcRuntime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+ObjcRuntime.m"; sourceTree = "<group>"; };
|
||||
C3F977812311B38F0032776D /* NSObject+Reflection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+Reflection.h"; sourceTree = "<group>"; };
|
||||
C3F977822311B38F0032776D /* NSObject+Reflection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Reflection.m"; sourceTree = "<group>"; };
|
||||
C3F977812311B38F0032776D /* NSObject+FLEX_Reflection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+FLEX_Reflection.h"; sourceTree = "<group>"; };
|
||||
C3F977822311B38F0032776D /* NSObject+FLEX_Reflection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+FLEX_Reflection.m"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -908,10 +912,10 @@
|
||||
3A4C94A61B5B21410088C3F2 /* FLEXObjectListViewController.m */,
|
||||
C3DB9F622107FC9600B46809 /* FLEXObjectRef.h */,
|
||||
C3DB9F632107FC9600B46809 /* FLEXObjectRef.m */,
|
||||
3A4C94A91B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.h */,
|
||||
3A4C94AA1B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.m */,
|
||||
679F64841BD53B7B00A8C94C /* FLEXCookiesTableViewController.h */,
|
||||
679F64851BD53B7B00A8C94C /* FLEXCookiesTableViewController.m */,
|
||||
3A4C94A91B5B21410088C3F2 /* FLEXLiveObjectsController.h */,
|
||||
3A4C94AA1B5B21410088C3F2 /* FLEXLiveObjectsController.m */,
|
||||
679F64841BD53B7B00A8C94C /* FLEXCookiesViewController.h */,
|
||||
679F64851BD53B7B00A8C94C /* FLEXCookiesViewController.m */,
|
||||
3A4C94AB1B5B21410088C3F2 /* FLEXWebViewController.h */,
|
||||
3A4C94AC1B5B21410088C3F2 /* FLEXWebViewController.m */,
|
||||
C39ED92622D63F3200B5773A /* FLEXAddressExplorerCoordinator.h */,
|
||||
@@ -950,10 +954,10 @@
|
||||
3A4C94BA1B5B21410088C3F2 /* FLEXNetworkSettingsController.m */,
|
||||
3A4C94BB1B5B21410088C3F2 /* FLEXNetworkTransaction.h */,
|
||||
3A4C94BC1B5B21410088C3F2 /* FLEXNetworkTransaction.m */,
|
||||
3A4C94BD1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.h */,
|
||||
3A4C94BE1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.m */,
|
||||
3A4C94BF1B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.h */,
|
||||
3A4C94C01B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.m */,
|
||||
3A4C94BD1B5B21410088C3F2 /* FLEXNetworkTransactionDetailController.h */,
|
||||
3A4C94BE1B5B21410088C3F2 /* FLEXNetworkTransactionDetailController.m */,
|
||||
3A4C94BF1B5B21410088C3F2 /* FLEXNetworkTransactionCell.h */,
|
||||
3A4C94C01B5B21410088C3F2 /* FLEXNetworkTransactionCell.m */,
|
||||
2EF6B04C1D494BE50006BDA5 /* FLEXNetworkCurlLogger.h */,
|
||||
2EF6B04B1D494BE50006BDA5 /* FLEXNetworkCurlLogger.m */,
|
||||
3A4C94C11B5B21410088C3F2 /* PonyDebugger */,
|
||||
@@ -987,8 +991,8 @@
|
||||
71E1C20F2307FBB700F5032A /* FLEXKeychain.m */,
|
||||
71E1C20D2307FBB700F5032A /* FLEXKeychainQuery.h */,
|
||||
71E1C2112307FBB700F5032A /* FLEXKeychainQuery.m */,
|
||||
71E1C20C2307FBB700F5032A /* FLEXKeychainTableViewController.h */,
|
||||
71E1C2102307FBB700F5032A /* FLEXKeychainTableViewController.m */,
|
||||
71E1C20C2307FBB700F5032A /* FLEXKeychainViewController.h */,
|
||||
71E1C2102307FBB700F5032A /* FLEXKeychainViewController.m */,
|
||||
);
|
||||
path = Keychain;
|
||||
sourceTree = "<group>";
|
||||
@@ -1084,8 +1088,8 @@
|
||||
children = (
|
||||
3A4C949F1B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.h */,
|
||||
3A4C94A01B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.m */,
|
||||
3A4C94A11B5B21410088C3F2 /* FLEXFileBrowserTableViewController.h */,
|
||||
3A4C94A21B5B21410088C3F2 /* FLEXFileBrowserTableViewController.m */,
|
||||
3A4C94A11B5B21410088C3F2 /* FLEXFileBrowserController.h */,
|
||||
3A4C94A21B5B21410088C3F2 /* FLEXFileBrowserController.m */,
|
||||
);
|
||||
path = FileBrowser;
|
||||
sourceTree = "<group>";
|
||||
@@ -1220,12 +1224,12 @@
|
||||
C398625C23AD6E90007E6793 /* UIFont+FLEX.m */,
|
||||
C383C3BC23B6B398007A321B /* UITextField+Range.h */,
|
||||
C383C3BB23B6B398007A321B /* UITextField+Range.m */,
|
||||
C383C3C023B6B429007A321B /* NSTimer+Blocks.h */,
|
||||
C383C3BF23B6B429007A321B /* NSTimer+Blocks.m */,
|
||||
C3BFD06E233C23ED0015FB82 /* NSArray+Functional.h */,
|
||||
C3BFD06F233C23ED0015FB82 /* NSArray+Functional.m */,
|
||||
C3F977812311B38F0032776D /* NSObject+Reflection.h */,
|
||||
C3F977822311B38F0032776D /* NSObject+Reflection.m */,
|
||||
C383C3C023B6B429007A321B /* NSTimer+FLEX.h */,
|
||||
C383C3BF23B6B429007A321B /* NSTimer+FLEX.m */,
|
||||
C3BFD06E233C23ED0015FB82 /* NSArray+FLEX.h */,
|
||||
C3BFD06F233C23ED0015FB82 /* NSArray+FLEX.m */,
|
||||
C3F977812311B38F0032776D /* NSObject+FLEX_Reflection.h */,
|
||||
C3F977822311B38F0032776D /* NSObject+FLEX_Reflection.m */,
|
||||
C3F9777F2311B38F0032776D /* NSDictionary+ObjcRuntime.h */,
|
||||
C3F9777E2311B38E0032776D /* NSDictionary+ObjcRuntime.m */,
|
||||
C3F9777D2311B38E0032776D /* NSString+ObjcRuntime.h */,
|
||||
@@ -1288,6 +1292,8 @@
|
||||
C398626F23AD71C6007E6793 /* DataSources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C3EB6F8C242E9C83006EA386 /* FLEXRuntimeExporter.h */,
|
||||
C3EB6F8B242E9C83006EA386 /* FLEXRuntimeExporter.m */,
|
||||
C398626723AD71C1007E6793 /* FLEXRuntimeClient.h */,
|
||||
C398626A23AD71C1007E6793 /* FLEXRuntimeClient.m */,
|
||||
C398626823AD71C1007E6793 /* FLEXRuntimeController.h */,
|
||||
@@ -1430,7 +1436,7 @@
|
||||
94A515141C4CA1C00063292F /* FLEXManager.h in Headers */,
|
||||
C37A0C93218BAC9600848CA7 /* FLEXObjcInternal.h in Headers */,
|
||||
C3A9422C23C3DA39006871A3 /* FHSView.h in Headers */,
|
||||
3A4C953E1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.h in Headers */,
|
||||
3A4C953E1B5B21410088C3F2 /* FLEXNetworkTransactionDetailController.h in Headers */,
|
||||
3A4C95301B5B21410088C3F2 /* FLEXSystemLogMessage.h in Headers */,
|
||||
C398625523AD6C67007E6793 /* FLEXObjcRuntimeViewController.h in Headers */,
|
||||
C3E5DA02231700EE00E655DB /* FLEXObjectInfoSection.h in Headers */,
|
||||
@@ -1480,7 +1486,7 @@
|
||||
C3A9424923C78878006871A3 /* FLEXHierarchyViewController.h in Headers */,
|
||||
C3DFCD942416BC6500BB7084 /* FLEXFilteringTableViewController.h in Headers */,
|
||||
3A4C94F11B5B21410088C3F2 /* FLEXArgumentInputFontsPickerView.h in Headers */,
|
||||
C3BFD070233C23ED0015FB82 /* NSArray+Functional.h in Headers */,
|
||||
C3BFD070233C23ED0015FB82 /* NSArray+FLEX.h in Headers */,
|
||||
C398682923AC370100E9E391 /* FLEXViewShortcuts.h in Headers */,
|
||||
C3474C4023DA496400466532 /* FLEXKeyValueTableViewCell.h in Headers */,
|
||||
779B1ED61C0C4D7C001F5E49 /* FLEXTableContentViewController.h in Headers */,
|
||||
@@ -1516,11 +1522,11 @@
|
||||
C36FBFDB230F3B98008D95D5 /* FLEXClassBuilder.h in Headers */,
|
||||
779B1ED41C0C4D7C001F5E49 /* FLEXDBQueryRowCell.h in Headers */,
|
||||
C301994A2409B38A00759E8E /* CALayer+FLEX.h in Headers */,
|
||||
3A4C952C1B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.h in Headers */,
|
||||
3A4C952C1B5B21410088C3F2 /* FLEXLiveObjectsController.h in Headers */,
|
||||
3A4C94EF1B5B21410088C3F2 /* FLEXArgumentInputDateView.h in Headers */,
|
||||
C36FBFCE230F3B98008D95D5 /* FLEXProperty.h in Headers */,
|
||||
C36FBFD2230F3B98008D95D5 /* FLEXMethodBase.h in Headers */,
|
||||
71E1C2142307FBB800F5032A /* FLEXKeychainTableViewController.h in Headers */,
|
||||
71E1C2142307FBB800F5032A /* FLEXKeychainViewController.h in Headers */,
|
||||
3A4C94F71B5B21410088C3F2 /* FLEXArgumentInputNotSupportedView.h in Headers */,
|
||||
C3F31D3E2267D883003C991A /* FLEXTableViewCell.h in Headers */,
|
||||
3A4C94E51B5B21410088C3F2 /* FLEXUtility.h in Headers */,
|
||||
@@ -1530,7 +1536,7 @@
|
||||
94A515251C4CA2080063292F /* FLEXExplorerToolbar.h in Headers */,
|
||||
C387C88322E0D24A00750E58 /* UIView+FLEX_Layout.h in Headers */,
|
||||
3A4C953C1B5B21410088C3F2 /* FLEXNetworkTransaction.h in Headers */,
|
||||
C383C3C223B6B429007A321B /* NSTimer+Blocks.h in Headers */,
|
||||
C383C3C223B6B429007A321B /* NSTimer+FLEX.h in Headers */,
|
||||
3A4C952E1B5B21410088C3F2 /* FLEXWebViewController.h in Headers */,
|
||||
C3A9424D23C78CFF006871A3 /* FHSViewSnapshot.h in Headers */,
|
||||
C3EE76BF22DFC63600EC0AA0 /* FLEXScopeCarousel.h in Headers */,
|
||||
@@ -1555,12 +1561,12 @@
|
||||
C38EF26323A2FCD20047A7EC /* FLEXViewControllerShortcuts.h in Headers */,
|
||||
3A4C95421B5B21410088C3F2 /* FLEXNetworkObserver.h in Headers */,
|
||||
C386D6EB24199E9600699085 /* FLEX-ObjectExploring.h in Headers */,
|
||||
679F64861BD53B7B00A8C94C /* FLEXCookiesTableViewController.h in Headers */,
|
||||
C3F977872311B38F0032776D /* NSObject+Reflection.h in Headers */,
|
||||
679F64861BD53B7B00A8C94C /* FLEXCookiesViewController.h in Headers */,
|
||||
C3F977872311B38F0032776D /* NSObject+FLEX_Reflection.h in Headers */,
|
||||
C3DB9F642107FC9600B46809 /* FLEXObjectRef.h in Headers */,
|
||||
3A4C95401B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.h in Headers */,
|
||||
3A4C95401B5B21410088C3F2 /* FLEXNetworkTransactionCell.h in Headers */,
|
||||
C398626523AD70F5007E6793 /* FLEXKBToolbarButton.h in Headers */,
|
||||
3A4C95241B5B21410088C3F2 /* FLEXFileBrowserTableViewController.h in Headers */,
|
||||
3A4C95241B5B21410088C3F2 /* FLEXFileBrowserController.h in Headers */,
|
||||
C31D93E423E38CBE005517BF /* FLEXBlockShortcuts.h in Headers */,
|
||||
94AAF0381BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.h in Headers */,
|
||||
71E1C2152307FBB800F5032A /* FLEXKeychainQuery.h in Headers */,
|
||||
@@ -1577,6 +1583,7 @@
|
||||
C3A9424023C5443A006871A3 /* FHSSnapshotNodes.h in Headers */,
|
||||
C32A195E231732E800EB02AC /* FLEXCollectionContentSection.h in Headers */,
|
||||
3A4C94E11B5B21410088C3F2 /* FLEXResources.h in Headers */,
|
||||
C3EB6F8E242E9C83006EA386 /* FLEXRuntimeExporter.h in Headers */,
|
||||
779B1ED81C0C4D7C001F5E49 /* FLEXTableLeftCell.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1713,11 +1720,12 @@
|
||||
3A4C95101B5B21410088C3F2 /* FLEXMethodCallingViewController.m in Sources */,
|
||||
C362AE8223C7E9D1005A86AE /* NSMapTable+FLEX_Subscripting.m in Sources */,
|
||||
C3F646C2239EAA8F00D4A011 /* UIPasteboard+FLEX.m in Sources */,
|
||||
C3EB6F8D242E9C83006EA386 /* FLEXRuntimeExporter.m in Sources */,
|
||||
3A4C94F61B5B21410088C3F2 /* FLEXArgumentInputObjectView.m in Sources */,
|
||||
3A4C94EC1B5B21410088C3F2 /* FLEXImagePreviewViewController.m in Sources */,
|
||||
C383C3BA23B6A62A007A321B /* FLEXRuntimeSafety.m in Sources */,
|
||||
3A4C94F21B5B21410088C3F2 /* FLEXArgumentInputFontsPickerView.m in Sources */,
|
||||
C3BFD071233C23ED0015FB82 /* NSArray+Functional.m in Sources */,
|
||||
C3BFD071233C23ED0015FB82 /* NSArray+FLEX.m in Sources */,
|
||||
7349FD6B22B93CDF00051810 /* FLEXColor.m in Sources */,
|
||||
C3878DBA23A749960038FDBE /* FLEXVariableEditorViewController.m in Sources */,
|
||||
94AAF0391BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.m in Sources */,
|
||||
@@ -1742,7 +1750,7 @@
|
||||
C36FBFDC230F3B98008D95D5 /* FLEXIvar.m in Sources */,
|
||||
C313854023F5C1A10046E63C /* FLEXViewControllersViewController.m in Sources */,
|
||||
C3F527C22318670F009CBA07 /* FLEXImageShortcuts.m in Sources */,
|
||||
679F64871BD53B7B00A8C94C /* FLEXCookiesTableViewController.m in Sources */,
|
||||
679F64871BD53B7B00A8C94C /* FLEXCookiesViewController.m in Sources */,
|
||||
C3A9422D23C3DA39006871A3 /* FHSView.m in Sources */,
|
||||
3A4C94CE1B5B21410088C3F2 /* FLEXGlobalsEntry.m in Sources */,
|
||||
C398625223AD6C67007E6793 /* FLEXKeyPathSearchController.m in Sources */,
|
||||
@@ -1765,13 +1773,13 @@
|
||||
3A4C95041B5B21410088C3F2 /* FLEXArgumentInputView.m in Sources */,
|
||||
C3F977842311B38F0032776D /* NSDictionary+ObjcRuntime.m in Sources */,
|
||||
C312A13523ECBE5800E38049 /* FLEXBookmarksViewController.m in Sources */,
|
||||
3A4C95411B5B21410088C3F2 /* FLEXNetworkTransactionTableViewCell.m in Sources */,
|
||||
3A4C95411B5B21410088C3F2 /* FLEXNetworkTransactionCell.m in Sources */,
|
||||
C3DFCD952416BC6500BB7084 /* FLEXFilteringTableViewController.m in Sources */,
|
||||
C3F527BE2318603F009CBA07 /* FLEXShortcutsSection.m in Sources */,
|
||||
3A4C94D61B5B21410088C3F2 /* FLEXObjectExplorerViewController.m in Sources */,
|
||||
C383C3BD23B6B398007A321B /* UITextField+Range.m in Sources */,
|
||||
3A4C94DE1B5B21410088C3F2 /* FLEXHeapEnumerator.m in Sources */,
|
||||
3A4C95251B5B21410088C3F2 /* FLEXFileBrowserTableViewController.m in Sources */,
|
||||
3A4C95251B5B21410088C3F2 /* FLEXFileBrowserController.m in Sources */,
|
||||
C36FBFD1230F3B98008D95D5 /* FLEXClassBuilder.m in Sources */,
|
||||
779B1ED51C0C4D7C001F5E49 /* FLEXDBQueryRowCell.m in Sources */,
|
||||
3A4C94E21B5B21410088C3F2 /* FLEXResources.m in Sources */,
|
||||
@@ -1810,11 +1818,11 @@
|
||||
3A4C95021B5B21410088C3F2 /* FLEXArgumentInputTextView.m in Sources */,
|
||||
C3531B9E23E69BB200A184AD /* FLEXManager+Networking.m in Sources */,
|
||||
C39EADC923F37B89005618BE /* FLEXTypeEncodingParser.m in Sources */,
|
||||
C3F977882311B38F0032776D /* NSObject+Reflection.m in Sources */,
|
||||
C3F977882311B38F0032776D /* NSObject+FLEX_Reflection.m in Sources */,
|
||||
C36B096623E0D4A1008F5D47 /* UIMenu+FLEX.m in Sources */,
|
||||
94A515261C4CA2080063292F /* FLEXExplorerToolbar.m in Sources */,
|
||||
C33C825F2316DC8600DD2451 /* FLEXObjectExplorer.m in Sources */,
|
||||
C383C3C123B6B429007A321B /* NSTimer+Blocks.m in Sources */,
|
||||
C383C3C123B6B429007A321B /* NSTimer+FLEX.m in Sources */,
|
||||
3A4C94FA1B5B21410088C3F2 /* FLEXArgumentInputNumberView.m in Sources */,
|
||||
C3474C4123DA496400466532 /* FLEXKeyValueTableViewCell.m in Sources */,
|
||||
779B1ED71C0C4D7C001F5E49 /* FLEXTableContentViewController.m in Sources */,
|
||||
@@ -1823,7 +1831,7 @@
|
||||
3A4C95001B5B21410088C3F2 /* FLEXArgumentInputSwitchView.m in Sources */,
|
||||
C386D6F02419A33F00699085 /* FLEXRuntimeConstants.m in Sources */,
|
||||
C3F31D442267D883003C991A /* FLEXTableView.m in Sources */,
|
||||
3A4C953F1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.m in Sources */,
|
||||
3A4C953F1B5B21410088C3F2 /* FLEXNetworkTransactionDetailController.m in Sources */,
|
||||
224D49AB1C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.m in Sources */,
|
||||
C312A13C23ECE79000E38049 /* FLEXWindowManagerController.m in Sources */,
|
||||
C36FBFDA230F3B98008D95D5 /* FLEXPropertyAttributes.m in Sources */,
|
||||
@@ -1834,7 +1842,7 @@
|
||||
C34D4EB923A2B17900C1F903 /* FLEXBundleShortcuts.m in Sources */,
|
||||
C3531BAB23E88FAC00A184AD /* FLEXTabList.m in Sources */,
|
||||
C3DFCD992416E7DD00BB7084 /* FLEXMutableListSection.m in Sources */,
|
||||
3A4C952D1B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.m in Sources */,
|
||||
3A4C952D1B5B21410088C3F2 /* FLEXLiveObjectsController.m in Sources */,
|
||||
C33E46B0223B02CD004BD0E6 /* FLEXASLLogController.m in Sources */,
|
||||
C398625023AD6C67007E6793 /* FLEXObjcRuntimeViewController.m in Sources */,
|
||||
C398626E23AD71C1007E6793 /* FLEXRuntimeClient.m in Sources */,
|
||||
@@ -1845,7 +1853,7 @@
|
||||
3A4C95291B5B21410088C3F2 /* FLEXObjectListViewController.m in Sources */,
|
||||
C397E319240EC98F0091E4EC /* FLEXSQLResult.m in Sources */,
|
||||
C31D93E923E38E97005517BF /* FLEXBlockDescription.m in Sources */,
|
||||
71E1C2182307FBB800F5032A /* FLEXKeychainTableViewController.m in Sources */,
|
||||
71E1C2182307FBB800F5032A /* FLEXKeychainViewController.m in Sources */,
|
||||
94A5151E1C4CA1F10063292F /* FLEXExplorerViewController.m in Sources */,
|
||||
C398625A23AD6C88007E6793 /* FLEXSearchToken.m in Sources */,
|
||||
3A4C95371B5B21410088C3F2 /* FLEXNetworkMITMViewController.m in Sources */,
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <objc/runtime.h>
|
||||
#import "NSObject+Reflection.h"
|
||||
#import "NSArray+Functional.h"
|
||||
#import "NSObject+FLEX_Reflection.h"
|
||||
#import "NSArray+FLEX.h"
|
||||
#import "FLEXPropertyAttributes.h"
|
||||
#import "FLEXProperty.h"
|
||||
#import "FLEXUtility.h"
|
||||
|
||||
Reference in New Issue
Block a user