1

注: この質問の冒頭は次の質問と似ています (最初の部分は同じです): LINK
ただし、最後の質問はまったく異なります。

私は「Code Injector Class」を実装しています。これにより、メソッドのスウィズリングにより、次のようなことが可能になります。

FLCodeInjector *injector = [FLCodeInjector injectorForClass:[self class]];
[injector injectCodeBeforeSelector:@selector(aSelector:) code:^{
    NSLog(@"This code should be injected");
}];

aSelector引数の数が可変で、戻り値の型が可変のメソッドにすることができます。引数 / および戻り値の型は、オブジェクトまたはプリミティブ型にすることができます。

最初に、私injectCodeBeforeSelector:が何をしているのかを理解してもらうために のコードを添付します (コードの重要でない部分を削除しました)。

- (void)injectCodeBeforeSelector:(SEL)method code:(void (^)())completionBlock
{

    NSString *selector = NSStringFromSelector(method);

    [self.dictionaryOfBlocks setObject:completionBlock forKey:selector];

    NSString *swizzleSelector = [NSString stringWithFormat:@"SWZ%@", selector];

    //NSMethodSignature *signature = [self.mainClass instanceMethodSignatureForSelector:method];

    // add a new method to the swizzled class
    Method origMethod = class_getInstanceMethod(self.mainClass, NSSelectorFromString(selector));
    const char *encoding = method_getTypeEncoding(origMethod);


    [self addSelector:NSSelectorFromString(swizzleSelector) toClass:self.mainClass originalSelector:method methodTypeEncoding:encoding];
    SwizzleMe(self.mainClass, NSSelectorFromString(selector), NSSelectorFromString(swizzleSelector));

}

    -(void)addSelector:(SEL)selector toClass:(Class)aClass originalSelector:(SEL)originalSel methodTypeEncoding:(const char *)encoding
{

    //NSMethodSignature *signature = [aClass methodSignatureForSelector:originalSel];
    NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:encoding];
    const char *type = [signature methodReturnType];
    IMP implementation = (IMP)intGenericFunction;


    if (strcmp(@encode(id), type) == 0) {
        // the argument is an object
        implementation = objectGenericFunction;
    }
    else if (strcmp(@encode(int), type) == 0)
    {
        // the argument is an int
        implementation = (IMP)intGenericFunction;
    }
    else if (strcmp(@encode(long), type) == 0)
    {
        // the argument is a long
        implementation = (IMP)longGenericFunction;

    }
    else if (strcmp(@encode(double), type) == 0)
    {
        // the argument is double
        implementation = (IMP)doubleGenericFunction;
    }
    else if (strcmp(@encode(float), type) == 0)
    {
        // the argument is float
        implementation = (IMP)floatGenericFunction;
    }
    else
    {
        // the argument is char or others
        implementation = (IMP)intGenericFunction;
    }



    class_addMethod(aClass,
                    selector,
                    implementation, encoding);
}

ここで何が起きてるの?基本的には、元のセレクターの予想される戻り値の型に基づいて、正しい戻り値の型を持つ新しいメソッドをオブジェクトに追加し、スウィズルを適用します。

すべてが正しく機能していますが、次のコードを「圧縮」できるかどうかを知りたいです (構文がわからない、または不足している)。戻り値の型ごとに次の関数があるためです。他のものとほぼ同じで、返される型だけが異なります。例として、そのうちの 2 つを添付します。

int intGenericFunction(id self, SEL cmd, ...) {

    FLCodeInjector *injector = [FLCodeInjector injectorForClass:[self class]];
    [injector executeBlockForSelector:cmd];


    va_list arguments, copiedArguments;
    va_start ( arguments, cmd );
    va_copy(copiedArguments, arguments);
    va_end(arguments);

    void * returnValue = getReturnValue(self, cmd, copiedArguments);

    int returnedInt = *(int *)returnValue;
    return returnedInt;
}

double doubleGenericFunction(id self, SEL cmd, ...) {

    FLCodeInjector *injector = [FLCodeInjector injectorForClass:[self class]];
    [injector executeBlockForSelector:cmd];


    va_list arguments, copiedArguments;
    va_start ( arguments, cmd );
    va_copy(copiedArguments, arguments);
    va_end(arguments);

    void * returnValue = getReturnValue(self, cmd, copiedArguments);

    double returnedDouble = *(double *)returnValue;
    return returnedDouble;
}

ご覧のとおり、関数はほぼ同じです。唯一の違いは、戻り値の前の CAST と、関数の戻り値の型です。

私は正しい方法で実装していますか、それともより効率的な方法がありますか? ありがとう

4

1 に答える 1

3

少なくとも、ディスパッチを行うためにアセンブリにドロップダウンしない限り、戻り値の型ごとに異なる IMP を記述する必要があることは正しいですobjc_msgSend。(ただし、その関数でさえ、いくつかの異なる型バリアントが必要です。)ただし、違いが本当に型名の数だけである場合は、ボイラープレートを削減するマクロを定義できる場合があります。

// This macro syntax is off the top of my head; it may not be correct.
#define GENERIC_FUNCTION_FOR_TYPE(type) type type##GenericFunction(id self, SEL cmd, ...) { \
    ...other lines omitted... \
    type returnedValue = *(type *)returnValue; \
    return returnedValue; \
}

GENERIC_FUNCTION_FOR_TYPE(int)
GENERIC_FUNCTION_FOR_TYPE(double)
...etc...
于 2013-08-08T13:22:17.933 に答える