NSInvocation+KiwiAdditions.m 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. //
  2. // Licensed under the terms in License.txt
  3. //
  4. // Copyright 2010 Allen Ding. All rights reserved.
  5. //
  6. #import "NSInvocation+KiwiAdditions.h"
  7. #import "KWFormatter.h"
  8. #import "KWObjCUtilities.h"
  9. #import "NSMethodSignature+KiwiAdditions.h"
  10. @implementation NSInvocation(KiwiAdditions)
  11. #pragma mark - Creating NSInvocation Objects
  12. + (NSInvocation *)invocationWithTarget:(id)anObject selector:(SEL)aSelector {
  13. return [self invocationWithTarget:anObject selector:aSelector messageArguments:nil];
  14. }
  15. + (NSInvocation *)invocationWithTarget:(id)anObject selector:(SEL)aSelector messageArguments:(const void *)firstBytes, ... {
  16. if (anObject == nil) {
  17. [NSException raise:NSInvalidArgumentException format:@"%@ - target must not be nil",
  18. NSStringFromSelector(_cmd)];
  19. }
  20. NSMethodSignature *signature = [anObject methodSignatureForSelector:aSelector];
  21. if (signature == nil) {
  22. [NSException raise:NSInvalidArgumentException format:@"%@ - target returned nil for -methodSignatureForSelector",
  23. NSStringFromSelector(_cmd)];
  24. }
  25. NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
  26. [invocation setTarget:anObject];
  27. [invocation setSelector:aSelector];
  28. NSUInteger numberOfMessageArguments = [signature numberOfMessageArguments];
  29. if (numberOfMessageArguments == 0)
  30. return invocation;
  31. va_list argumentList;
  32. va_start(argumentList, firstBytes);
  33. const void *bytes = firstBytes;
  34. for (NSUInteger i = 0; i < numberOfMessageArguments && bytes != nil; ++i) {
  35. [invocation setMessageArgument:bytes atIndex:i];
  36. bytes = va_arg(argumentList, const void *);
  37. }
  38. va_end(argumentList);
  39. return invocation;
  40. }
  41. #pragma mark - Accessing Message Arguments
  42. - (NSData *)messageArgumentDataAtIndex:(NSUInteger)anIndex {
  43. NSUInteger length = KWObjCTypeLength([[self methodSignature] messageArgumentTypeAtIndex:anIndex]);
  44. void *buffer = malloc(length);
  45. [self getMessageArgument:buffer atIndex:anIndex];
  46. // NSData takes over ownership of buffer
  47. NSData* data = [NSData dataWithBytesNoCopy:buffer length:length];
  48. return data;
  49. }
  50. - (void)getMessageArgument:(void *)buffer atIndex:(NSUInteger)anIndex {
  51. [self getArgument:buffer atIndex:anIndex + 2];
  52. }
  53. - (void)setMessageArgument:(const void *)bytes atIndex:(NSUInteger)anIndex {
  54. [self setArgument:(void *)bytes atIndex:anIndex + 2];
  55. }
  56. - (void)setMessageArguments:(const void *)firstBytes, ... {
  57. NSUInteger numberOfMessageArguments = [[self methodSignature] numberOfMessageArguments];
  58. if (numberOfMessageArguments == 0)
  59. return;
  60. va_list argumentList;
  61. va_start(argumentList, firstBytes);
  62. const void *bytes = firstBytes;
  63. for (NSUInteger i = 0; i < numberOfMessageArguments && bytes != nil; ++i) {
  64. [self setMessageArgument:bytes atIndex:i];
  65. bytes = va_arg(argumentList, const void *);
  66. }
  67. va_end(argumentList);
  68. }
  69. @end