天天看點

利用NSInvocation對方法進行抽象,實作對方法的加鎖

我們在實際開發中需要對離散的方式加鎖實作線程安全,當然我們有多種實作方式,這隻是其中一種,使用起來比較友善

+ (id)performSelectorWithTarget:(id)target selector:(SEL)selector withObject:(id)arg1 ,...NS_REQUIRES_NIL_TERMINATION;

{

    @synchronized(self){

        id result = nil;

        NSMethodSignature *sig = [target methodSignatureForSelector:selector];

        if (!sig) return result;

        NSInvocation* myInvocation = [NSInvocation invocationWithMethodSignature:sig];

        [myInvocation setTarget:target];

        [myInvocation setSelector:selector];

        int argumentStart = 2;

        va_list args;

        va_start(args, arg1); // scan for arguments after firstObject.

        // get rest of the objects until nil is found

        for (id obj = arg1; obj != nil; obj = va_arg(args,id)) {

            [myInvocation setArgument:&obj atIndex:argumentStart];

            argumentStart++;

        }

        va_end(args);

        [myInvocation retainArguments];

        [myInvocation invoke];

        //獲得傳回值類型

        const char *returnType = sig.methodReturnType;

        //聲明傳回值變量

        //如果沒有傳回值,也就是消息聲明為void,那麼returnValue=nil

        if( !strcmp(returnType, @encode(void)) ){

            result =  nil;

        }

        //如果傳回值為對象,那麼為變量指派

        else if( !strcmp(returnType, @encode(id)) ){

            [myInvocation getReturnValue: &result];

        }else{

            //如果傳回值為普通類型NSInteger  BOOL

            //傳回值長度

            NSUInteger length = [sig methodReturnLength];

            //根據長度申請記憶體

            void *buffer = (void *)malloc(length);

            //為變量指派

            [myInvocation getReturnValue:buffer];

            if( !strcmp(returnType, @encode(BOOL)) ) {

                result = [NSNumber numberWithBool:*((BOOL*)buffer)];

            }

            else if( !strcmp(returnType, @encode(NSInteger)) ){

                result = [NSNumber numberWithInteger:*((NSInteger*)buffer)];

            }else {

                result = [NSValue valueWithBytes:buffer objCType:returnType];

            }

            free(buffer);

        }

        return result;

    }

}

繼續閱讀