FLEXMethodCallingViewController.m 3.6 KB

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