FLEXMethodCallingViewController.m 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. //
  2. // FLEXMethodCallingViewController.m
  3. // Flipboard
  4. //
  5. // Created by Ryan Olson on 5/23/14.
  6. // Copyright (c) 2020 FLEX Team. All rights reserved.
  7. //
  8. #import "FLEXMethodCallingViewController.h"
  9. #import "FLEXRuntimeUtility.h"
  10. #import "FLEXFieldEditorView.h"
  11. #import "FLEXObjectExplorerFactory.h"
  12. #import "FLEXObjectExplorerViewController.h"
  13. #import "FLEXArgumentInputView.h"
  14. #import "FLEXArgumentInputViewFactory.h"
  15. #import "FLEXUtility.h"
  16. @interface FLEXMethodCallingViewController ()
  17. @property (nonatomic, readonly) FLEXMethod *method;
  18. @end
  19. @implementation FLEXMethodCallingViewController
  20. + (instancetype)target:(id)target method:(FLEXMethod *)method {
  21. return [[self alloc] initWithTarget:target method:method];
  22. }
  23. - (id)initWithTarget:(id)target method:(FLEXMethod *)method {
  24. NSParameterAssert(method.isInstanceMethod == !object_isClass(target));
  25. self = [super initWithTarget:target data:method commitHandler:nil];
  26. if (self) {
  27. self.title = method.isInstanceMethod ? @"Method: " : @"Class Method: ";
  28. self.title = [self.title stringByAppendingString:method.selectorString];
  29. }
  30. return self;
  31. }
  32. - (void)viewDidLoad {
  33. [super viewDidLoad];
  34. self.actionButton.title = @"Call";
  35. // Configure field editor view
  36. self.fieldEditorView.argumentInputViews = [self argumentInputViews];
  37. self.fieldEditorView.fieldDescription = [NSString stringWithFormat:
  38. @"Signature:\n%@\n\nReturn Type:\n%s",
  39. self.method.description, (char *)self.method.returnType
  40. ];
  41. }
  42. - (NSArray<FLEXArgumentInputView *> *)argumentInputViews {
  43. Method method = self.method.objc_method;
  44. NSArray *methodComponents = [FLEXRuntimeUtility prettyArgumentComponentsForMethod:method];
  45. NSMutableArray<FLEXArgumentInputView *> *argumentInputViews = [NSMutableArray new];
  46. unsigned int argumentIndex = kFLEXNumberOfImplicitArgs;
  47. for (NSString *methodComponent in methodComponents) {
  48. char *argumentTypeEncoding = method_copyArgumentType(method, argumentIndex);
  49. FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:argumentTypeEncoding];
  50. free(argumentTypeEncoding);
  51. inputView.backgroundColor = self.view.backgroundColor;
  52. inputView.title = methodComponent;
  53. [argumentInputViews addObject:inputView];
  54. argumentIndex++;
  55. }
  56. return argumentInputViews;
  57. }
  58. - (void)actionButtonPressed:(id)sender {
  59. // Gather arguments
  60. NSMutableArray *arguments = [NSMutableArray new];
  61. for (FLEXArgumentInputView *inputView in self.fieldEditorView.argumentInputViews) {
  62. // Use NSNull as a nil placeholder; it will be interpreted as nil
  63. [arguments addObject:inputView.inputValue ?: NSNull.null];
  64. }
  65. // Call method
  66. NSError *error = nil;
  67. id returnValue = [FLEXRuntimeUtility
  68. performSelector:self.method.selector
  69. onObject:self.target
  70. withArguments:arguments
  71. error:&error
  72. ];
  73. // Dismiss keyboard and handle committed changes
  74. [super actionButtonPressed:sender];
  75. // Display return value or error
  76. if (error) {
  77. [FLEXAlert showAlert:@"Method Call Failed" message:error.localizedDescription from:self];
  78. } else if (returnValue) {
  79. // For non-nil (or void) return types, push an explorer view controller to display the returned object
  80. returnValue = [FLEXRuntimeUtility potentiallyUnwrapBoxedPointer:returnValue type:self.method.returnType];
  81. FLEXObjectExplorerViewController *explorer = [FLEXObjectExplorerFactory explorerViewControllerForObject:returnValue];
  82. [self.navigationController pushViewController:explorer animated:YES];
  83. } else {
  84. [self exploreObjectOrPopViewController:returnValue];
  85. }
  86. }
  87. - (FLEXMethod *)method {
  88. return _data;
  89. }
  90. @end