HWInvocation 利用了 Objective-C 的 Variable Arguments 功能,不用 call 無數個 setArgument,可以在 constructor 中一次過輸入所有 arguments。
另外 Sample Code 中示範了怎樣傳 NSObject 和非 NSObject 類變數到 NSInvocation 中,其秘訣是使用 address of (&) 去取得 memory address (pointer)。
SampleCode.m
#import "HWInvocation.h"
// ... other code skipped ...
+ (void)setSomething:(BOOL)yesOrNo str:(NSString *)string
{
NSLog(@"setSomething: %@ - %@",(yesOrNo == YES ? @"YES" : @"NO"),string);
}
- (void)setOtherThing:(int)num str:(NSString *)string
{
NSLog(@"setOtherThing: %d - %@",num,string);
}
- testInvocation {
NSString *str = @"Testing HWInvocation";
BOOL yes = YES;
int num = 123;
NSInvocation *invocation;
invocation = [NSInvocation classMethodInvocationWithSelectorName:@"setSomething:str:" baseClass:[SampleCode class] args:&yes,&str];
[invocation tryInvoke];
invocation = [NSInvocation invocationWithSelectorName:@"setOtherThing:str:" target:self args:&num,&str];
[invocation tryInvoke];
}
HWInvocation.h
#import <Foundation/Foundation.h> @interface NSInvocation (HWInvocation) + (NSInvocation *)classMethodInvocationWithSelectorName:(NSString *)selname baseClass:(Class)class args:(void *)buffer, ...; + (NSInvocation *)invocationWithSelectorName:(NSString *)selname target:(id)target args:(void *)buffer, ...; - (BOOL)tryInvoke; @endHWInvocation.m
#import "HWInvocation.h"
#import <objc/runtime.h> // Needed for the ISA pointer
@implementation NSInvocation (HWInvocation)
+ (NSInvocation *)classMethodInvocationWithSelectorName:(NSString *)selname baseClass:(Class)class args:(void *)buffer, ...
{
SEL aSelector;
NSMethodSignature *signature;
NSInvocation *invocation;
int numOfArgs;
int i = 3; // Index to place the first variable argument
void *buf;
va_list argumentList;
aSelector = NSSelectorFromString(selname);
if (aSelector == NULL) return nil;
signature = [class->isa instanceMethodSignatureForSelector:aSelector];
if (signature == nil) return nil;
numOfArgs = [signature numberOfArguments];
invocation = [NSInvocation invocationWithMethodSignature:signature];
if (invocation == nil) return nil;
[invocation setTarget:class];
[invocation setSelector:aSelector];
if (numOfArgs >= i)
{
[invocation setArgument:buffer atIndex:2];
va_start(argumentList, buffer);
while (i < numOfArgs)
{
buf = va_arg(argumentList, id);
[invocation setArgument:buf atIndex:i++];
}
va_end(argumentList);
}
return invocation;
}
+ (NSInvocation *)invocationWithSelectorName:(NSString *)selname target:(id)target args:(void *)buffer, ...
{
SEL aSelector;
NSMethodSignature *signature;
NSInvocation *invocation;
int numOfArgs;
int i = 3; // Index to place the first variable argument
void *buf;
va_list argumentList;
aSelector = NSSelectorFromString(selname);
if (aSelector == NULL) return nil;
signature = [target methodSignatureForSelector:aSelector];
if (signature == nil) return nil;
numOfArgs = [signature numberOfArguments];
invocation = [NSInvocation invocationWithMethodSignature:signature];
if (invocation == nil) return nil;
[invocation setTarget:target];
[invocation setSelector:aSelector];
if (numOfArgs >= i)
{
[invocation setArgument:buffer atIndex:2];
va_start(argumentList, buffer);
while (i < numOfArgs)
{
buf = va_arg(argumentList, id);
[invocation setArgument:buf atIndex:i++];
}
va_end(argumentList);
}
return invocation;
}
- (BOOL)tryInvoke
{
@try
{
[self invoke];
return YES;
}
@catch (NSException * e)
{
NSLog(@"Invoke failed: %@",NSStringFromSelector([self selector]));
return NO;
}
return NO;
}
@end
沒有留言:
張貼留言