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