FLEXLibrariesTableViewController.m 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //
  2. // FLEXLibrariesTableViewController.m
  3. // Flipboard
  4. //
  5. // Created by Ryan Olson on 2014-05-02.
  6. // Copyright (c) 2014 Flipboard. All rights reserved.
  7. //
  8. #import "FLEXLibrariesTableViewController.h"
  9. #import "FLEXUtility.h"
  10. #import "FLEXClassesTableViewController.h"
  11. #import "FLEXClassExplorerViewController.h"
  12. #import <objc/runtime.h>
  13. @interface FLEXLibrariesTableViewController ()
  14. @property (nonatomic, strong) NSArray<NSString *> *imageNames;
  15. @property (nonatomic, strong) NSArray<NSString *> *filteredImageNames;
  16. @property (nonatomic, strong) Class foundClass;
  17. @end
  18. @implementation FLEXLibrariesTableViewController
  19. - (id)initWithStyle:(UITableViewStyle)style
  20. {
  21. self = [super initWithStyle:style];
  22. if (self) {
  23. [self loadImageNames];
  24. }
  25. return self;
  26. }
  27. - (void)viewDidLoad
  28. {
  29. [super viewDidLoad];
  30. self.showsSearchBar = YES;
  31. }
  32. #pragma mark - Binary Images
  33. - (void)loadImageNames
  34. {
  35. unsigned int imageNamesCount = 0;
  36. const char **imageNames = objc_copyImageNames(&imageNamesCount);
  37. if (imageNames) {
  38. NSMutableArray<NSString *> *imageNameStrings = [NSMutableArray array];
  39. NSString *appImageName = [FLEXUtility applicationImageName];
  40. for (unsigned int i = 0; i < imageNamesCount; i++) {
  41. const char *imageName = imageNames[i];
  42. NSString *imageNameString = [NSString stringWithUTF8String:imageName];
  43. // Skip the app's image. We're just showing system libraries and frameworks.
  44. if (![imageNameString isEqual:appImageName]) {
  45. [imageNameStrings addObject:imageNameString];
  46. }
  47. }
  48. // Sort alphabetically
  49. self.imageNames = [imageNameStrings sortedArrayWithOptions:0 usingComparator:^NSComparisonResult(NSString *name1, NSString *name2) {
  50. NSString *shortName1 = [self shortNameForImageName:name1];
  51. NSString *shortName2 = [self shortNameForImageName:name2];
  52. return [shortName1 caseInsensitiveCompare:shortName2];
  53. }];
  54. free(imageNames);
  55. }
  56. }
  57. - (NSString *)shortNameForImageName:(NSString *)imageName
  58. {
  59. NSArray<NSString *> *components = [imageName componentsSeparatedByString:@"/"];
  60. if (components.count >= 2) {
  61. return [NSString stringWithFormat:@"%@/%@", components[components.count - 2], components[components.count - 1]];
  62. }
  63. return imageName.lastPathComponent;
  64. }
  65. - (void)setImageNames:(NSArray<NSString *> *)imageNames
  66. {
  67. if (![_imageNames isEqual:imageNames]) {
  68. _imageNames = imageNames;
  69. self.filteredImageNames = imageNames;
  70. }
  71. }
  72. #pragma mark - Filtering
  73. - (void)updateSearchResults:(NSString *)searchText
  74. {
  75. if (searchText.length) {
  76. NSPredicate *searchPredicate = [NSPredicate predicateWithBlock:^BOOL(NSString *evaluatedObject, NSDictionary<NSString *, id> *bindings) {
  77. BOOL matches = NO;
  78. NSString *shortName = [self shortNameForImageName:evaluatedObject];
  79. if ([shortName rangeOfString:searchText options:NSCaseInsensitiveSearch].length > 0) {
  80. matches = YES;
  81. }
  82. return matches;
  83. }];
  84. self.filteredImageNames = [self.imageNames filteredArrayUsingPredicate:searchPredicate];
  85. } else {
  86. self.filteredImageNames = self.imageNames;
  87. }
  88. self.foundClass = NSClassFromString(searchText);
  89. [self.tableView reloadData];
  90. }
  91. #pragma mark - Table View Data Source
  92. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  93. {
  94. return 1;
  95. }
  96. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  97. {
  98. return self.filteredImageNames.count + (self.foundClass ? 1 : 0);
  99. }
  100. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  101. {
  102. static NSString *cellIdentifier = @"Cell";
  103. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
  104. if (!cell) {
  105. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
  106. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  107. cell.textLabel.font = [FLEXUtility defaultTableViewCellLabelFont];
  108. }
  109. NSString *executablePath;
  110. if (self.foundClass) {
  111. if (indexPath.row == 0) {
  112. cell.textLabel.text = [NSString stringWithFormat:@"Class \"%@\"", self.searchText];
  113. return cell;
  114. } else {
  115. executablePath = self.filteredImageNames[indexPath.row-1];
  116. }
  117. } else {
  118. executablePath = self.filteredImageNames[indexPath.row];
  119. }
  120. cell.textLabel.text = [self shortNameForImageName:executablePath];
  121. return cell;
  122. }
  123. #pragma mark - Table View Delegate
  124. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  125. {
  126. if (indexPath.row == 0 && self.foundClass) {
  127. FLEXClassExplorerViewController *objectExplorer = [FLEXClassExplorerViewController new];
  128. objectExplorer.object = self.foundClass;
  129. [self.navigationController pushViewController:objectExplorer animated:YES];
  130. } else {
  131. FLEXClassesTableViewController *classesViewController = [[FLEXClassesTableViewController alloc] init];
  132. classesViewController.binaryImageName = self.filteredImageNames[self.foundClass ? indexPath.row-1 : indexPath.row];
  133. [self.navigationController pushViewController:classesViewController animated:YES];
  134. }
  135. }
  136. @end