NSInvocationをカテゴリで拡張した¶
[NSObject valueForKey:(NSString*)inKey]はプリミティブ型をNSNumberやNSValueでラップする。
つまりKVCを使うと、ラップ済みのオブジェクトを取得する事が出来る。ただし、この場合呼出すメソッドに引数が有ってはならない。
引数がある場合はどうするか?NSInvocationを使えば出来る。
但し、[NSInvocation getReturnValue:(void*)inPtr]で取得出来る返り値の型(void*)だ。 この返り値の型は、[NSInvocation methodReturnType]で取得出来る。当然プリミティブ型も含まれる。
この2つの値を参照してObject型を返すようなメソッドを作った。
@implementation NSInvocation (MTLAddition)
- (id) objectWrappedReturnValue
{
NSMethodSignature* theSignature = [self methodSignature];
const char* theReturnType = [theSignature methodReturnType];
void* thePtr = malloc([theSignature methodReturnLength]);
[self getReturnValue:thePtr];
id theResult = nil;
if( 0 == strcmp(theReturnType, @encode(id)) )
{
theResult = *(id*)thePtr;
}
else if( 0 == strcmp(theReturnType, @encode(Class)) )
{
theResult = *(Class*)thePtr;
}
else if( 0 == strcmp(theReturnType, @encode(char)) )
{
theResult = [NSNumber numberWithChar:*(char*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(unsigned char)) )
{
theResult = [NSNumber numberWithUnsignedChar:*(unsigned char*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(short)) )
{
theResult = [NSNumber numberWithShort:*(short*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(unsigned short)) )
{
theResult = [NSNumber numberWithUnsignedShort:*(unsigned short*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(int)) )
{
theResult = [NSNumber numberWithInt:*(int*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(unsigned int)) )
{
theResult = [NSNumber numberWithUnsignedInt:*(unsigned int*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(long)) )
{
theResult = [NSNumber numberWithLong:*(long*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(unsigned long)) )
{
theResult = [NSNumber numberWithUnsignedLong:*(unsigned long*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(long long)) )
{
theResult = [NSNumber numberWithLongLong:*(long long*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(unsigned long long)) )
{
theResult = [NSNumber numberWithUnsignedLongLong:*(unsigned long long*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(float)) )
{
theResult = [NSNumber numberWithFloat:*(float*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(double)) )
{
theResult = [NSNumber numberWithDouble:*(double*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(BOOL)) )
{
theResult = [NSNumber numberWithBool:*(BOOL*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(NSInteger)) )
{
theResult = [NSNumber numberWithInteger:*(NSInteger*)thePtr];
}
else if( 0 == strcmp(theReturnType, @encode(NSUInteger)) )
{
theResult = [NSNumber numberWithUnsignedInteger:*(NSUInteger*)thePtr];
}
else
{
theResult = [NSValue valueWithBytes:thePtr
objCType:theReturnType];
}
free(thePtr);
return theResult;
}
@end
コードを見れば判るようにid型、Class型、NSNumberでサポートしているプリミティブ型の三つしか対応していない。
それ以外は、[NSValue valueWithBytes:(void*)inPtr objCType:(const char*)inType]を使っている。
かなりおおざっぱな実装だが、私の用途には十分だった。ポインター型、構造体、配列型、blocks型等も実装するべきなのだろうが、やり方が判らなかった。
Comments
comments powered by Disqus