performSelector多个参数

需求如题所示。。。。。 我们都知道

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

在NSObject中帮selector传递的参数个数最多是 2个 ,当时有时候如果某种需求。。。需要2个以上的参数该如何搞一搞了 ??? 其实网上有很多的例子


#import "NSObject+ArrayObjects.h"

@implementation NSObject (ArrayObjects)
-(id)performSelector:(SEL)aSelector withArray:(NSArray *)objects{

    if (aSelector == nil || objects == nil) {
         @throw [NSException exceptionWithName:@"NullExcetption" reason: @"aSelector or objects is null" userInfo:nil];
        return nil;
    }
    NSMethodSignature *methodSignature = [[self class] instanceMethodSignatureForSelector:aSelector];
    if(methodSignature == nil)
    {
        @throw [NSException exceptionWithName:@"FunctionNotFoundExcetption" reason: [NSString stringWithFormat:@"the %@ not found",NSStringFromSelector(aSelector)] userInfo:nil];
        return nil;
    }
    else
    {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
        [invocation setTarget:self];
        [invocation setSelector:aSelector];

        //签名中方法参数的个数,内部包含了self和_cmd,所以参数从第3个开始
        NSInteger  signatureParamCount = methodSignature.numberOfArguments - 2;
        NSInteger requireParamCount = objects.count;
        NSInteger resultParamCount = MIN(signatureParamCount, requireParamCount);
        for (NSInteger i = 0; i < resultParamCount; i++) {
            id  obj = objects[i];
            [invocation setArgument:&obj atIndex:i+2];
        }
        [invocation invoke];

        id callBackObject = nil;
        if(methodSignature.methodReturnLength)
        {
            [invocation getReturnValue:&callBackObject];
        }
        return callBackObject;
    }
}
@end

虽然这个一度娘就能度到,而且感觉很牛逼,其实是有bug和缺陷性的,然后对数组里面的数据有要求,我们都知道OC是兼容C代码的。。往里面放入block或结构体就瞎了。。。。。。 我在测试AFNetworking项目的时候发现上面代码存在问题,然后找到了一个比较好一点的解决方案 ,当然github上搞一搞的 ,感觉还可以没报错

#import <Foundation/Foundation.h>


@interface NSObject (VKMsgSend)

+ (id)VKCallSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...;

+ (id)VKCallSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...;

- (id)VKCallSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...;

- (id)VKCallSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...;

@end

@interface NSString (VKMsgSend)

- (id)VKCallClassSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...;

- (id)VKCallClassSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...;

- (id)VKCallClassAllocInitSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...;

- (id)VKCallClassAllocInitSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...;

@end
#import "VKMsgSend.h"

#if TARGET_OS_IPHONE
#import <UIKit/UIApplication.h>
#endif


#pragma mark : vk_nilObject

@interface vk_pointer : NSObject

@property (nonatomic) void *pointer;

@end

@implementation vk_pointer

@end

@interface vk_nilObject : NSObject

@end

@implementation vk_nilObject

@end

#pragma mark : static

static NSLock *_vkMethodSignatureLock;
static NSMutableDictionary *_vkMethodSignatureCache;
static vk_nilObject *vknilPointer = nil;

static NSString *vk_extractStructName(NSString *typeEncodeString){

    NSArray *array = [typeEncodeString componentsSeparatedByString:@"="];
    NSString *typeString = array[0];
    __block int firstVaildIndex = 0;
    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        unichar c = [typeEncodeString characterAtIndex:idx];
        if (c=='{'||c=='_') {
            firstVaildIndex++;
        }else{
            *stop = YES;
        }
    }];
    return [typeString substringFromIndex:firstVaildIndex];
}

static NSString *vk_selectorName(SEL selector){
    const char *selNameCstr = sel_getName(selector);
    NSString *selName = [[NSString alloc]initWithUTF8String:selNameCstr];
    return selName;
}

static NSMethodSignature *vk_getMethodSignature(Class cls, SEL selector){

    if (!_vkMethodSignatureLock) {
        _vkMethodSignatureLock =  [[NSLock alloc] init];
    }

    [_vkMethodSignatureLock lock];

    if (!_vkMethodSignatureCache) {
        _vkMethodSignatureCache = [[NSMutableDictionary alloc]init];
    }
    if (!_vkMethodSignatureCache[cls]) {
        _vkMethodSignatureCache[(id<NSCopying>)cls] =[[NSMutableDictionary alloc]init];
    }
    NSString *selName = vk_selectorName(selector);
    NSMethodSignature *methodSignature = _vkMethodSignatureCache[cls][selName];
    if (!methodSignature) {
        methodSignature = [cls instanceMethodSignatureForSelector:selector];
        if (methodSignature) {
            _vkMethodSignatureCache[cls][selName] = methodSignature;
        }else
        {
            methodSignature = [cls methodSignatureForSelector:selector];
            if (methodSignature) {
                _vkMethodSignatureCache[cls][selName] = methodSignature;
            }
        }
    }
    [_vkMethodSignatureLock unlock];
    return methodSignature;
}

static void vk_generateError(NSString *errorInfo, NSError **error){
    if (error) {
        *error = [NSError errorWithDomain:errorInfo code:0 userInfo:nil];
    }
}

static id vk_targetCallSelectorWithArgumentError(id target, SEL selector, NSArray *argsArr, NSError *__autoreleasing *error){

    Class cls = [target class];
    NSMethodSignature *methodSignature = vk_getMethodSignature(cls, selector);
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
    [invocation setTarget:target];
    [invocation setSelector:selector];

    NSMutableArray* _markArray;

    for (NSUInteger i = 2; i< [methodSignature numberOfArguments]; i++) {
        const char *argumentType = [methodSignature getArgumentTypeAtIndex:i];
        id valObj = argsArr[i-2];
        switch (argumentType[0]=='r'?argumentType[1]:argumentType[0]) {
            #define VK_CALL_ARG_CASE(_typeString, _type, _selector) \
            case _typeString: {                              \
            _type value = [valObj _selector];                     \
            [invocation setArgument:&value atIndex:i];\
            break; \
            }
                VK_CALL_ARG_CASE('c', char, charValue)
                VK_CALL_ARG_CASE('C', unsigned char, unsignedCharValue)
                VK_CALL_ARG_CASE('s', short, shortValue)
                VK_CALL_ARG_CASE('S', unsigned short, unsignedShortValue)
                VK_CALL_ARG_CASE('i', int, intValue)
                VK_CALL_ARG_CASE('I', unsigned int, unsignedIntValue)
                VK_CALL_ARG_CASE('l', long, longValue)
                VK_CALL_ARG_CASE('L', unsigned long, unsignedLongValue)
                VK_CALL_ARG_CASE('q', long long, longLongValue)
                VK_CALL_ARG_CASE('Q', unsigned long long, unsignedLongLongValue)
                VK_CALL_ARG_CASE('f', float, floatValue)
                VK_CALL_ARG_CASE('d', double, doubleValue)
                VK_CALL_ARG_CASE('B', BOOL, boolValue)

            case ':':{
                NSString *selName = valObj;
                SEL selValue = NSSelectorFromString(selName);
                [invocation setArgument:&selValue atIndex:i];
            }
                break;
            case '{':{
                NSString *typeString = vk_extractStructName([NSString stringWithUTF8String:argumentType]);
                NSValue *val = (NSValue *)valObj;
            #define vk_CALL_ARG_STRUCT(_type, _methodName) \
            if ([typeString rangeOfString:@#_type].location != NSNotFound) {    \
            _type value = [val _methodName];  \
            [invocation setArgument:&value atIndex:i];  \
            break; \
            }
                            vk_CALL_ARG_STRUCT(CGRect, CGRectValue)
                            vk_CALL_ARG_STRUCT(CGPoint, CGPointValue)
                            vk_CALL_ARG_STRUCT(CGSize, CGSizeValue)
                            vk_CALL_ARG_STRUCT(NSRange, rangeValue)
                            vk_CALL_ARG_STRUCT(CGAffineTransform, CGAffineTransformValue)
                            vk_CALL_ARG_STRUCT(UIEdgeInsets, UIEdgeInsetsValue)
                            vk_CALL_ARG_STRUCT(UIOffset, UIOffsetValue)
                            vk_CALL_ARG_STRUCT(CGVector, CGVectorValue)
            }
                break;
            case '*':{
                NSCAssert(NO, @"argument boxing wrong,char* is not supported");
            }
                break;
            case '^':{
                vk_pointer *value = valObj;
                void *pointer = value.pointer;
                id obj = *((__unsafe_unretained id *)pointer);
                if (!obj) {
                    if (argumentType[1] == '@') {
                        if (!_markArray) {
                            _markArray = [[NSMutableArray alloc] init];
                        }
                        [_markArray addObject:valObj];
                    }
                }
                [invocation setArgument:&pointer atIndex:i];
            }
                break;
            case '#':{
                [invocation setArgument:&valObj atIndex:i];
            }
                break;
            default:{
                if ([valObj isKindOfClass:[vk_nilObject class]]) {
                    [invocation setArgument:&vknilPointer atIndex:i];
                }else{
                    [invocation setArgument:&valObj atIndex:i];
                }
            }
        }
    }

    [invocation invoke];

    if ([_markArray count] > 0) {
        for (vk_pointer *pointerObj in _markArray) {
            void *pointer = pointerObj.pointer;
            id obj = *((__unsafe_unretained id *)pointer);
            if (obj) {
                CFRetain((__bridge CFTypeRef)(obj));
            }
        }
    }

    const char *returnType = [methodSignature methodReturnType];
    NSString *selName = vk_selectorName(selector);
    if (strncmp(returnType, "v", 1) != 0 ) {
        if (strncmp(returnType, "@", 1) == 0) {
            void *result;
            [invocation getReturnValue:&result];

            if (result == NULL) {
                return nil;
            }

            id returnValue;
            if ([selName isEqualToString:@"alloc"] || [selName isEqualToString:@"new"] || [selName isEqualToString:@"copy"] || [selName isEqualToString:@"mutableCopy"]) {
                returnValue = (__bridge_transfer id)result;
            }else{
                returnValue = (__bridge id)result;
            }
            return returnValue;

        } else {
            switch (returnType[0] == 'r' ? returnType[1] : returnType[0]) {

            #define vk_CALL_RET_CASE(_typeString, _type) \
            case _typeString: {                              \
            _type returnValue; \
            [invocation getReturnValue:&returnValue];\
            return @(returnValue); \
            break; \
            }
                                vk_CALL_RET_CASE('c', char)
                                vk_CALL_RET_CASE('C', unsigned char)
                                vk_CALL_RET_CASE('s', short)
                                vk_CALL_RET_CASE('S', unsigned short)
                                vk_CALL_RET_CASE('i', int)
                                vk_CALL_RET_CASE('I', unsigned int)
                                vk_CALL_RET_CASE('l', long)
                                vk_CALL_RET_CASE('L', unsigned long)
                                vk_CALL_RET_CASE('q', long long)
                                vk_CALL_RET_CASE('Q', unsigned long long)
                                vk_CALL_RET_CASE('f', float)
                                vk_CALL_RET_CASE('d', double)
                                vk_CALL_RET_CASE('B', BOOL)

                case '{': {
                    NSString *typeString = vk_extractStructName([NSString stringWithUTF8String:returnType]);
                #define vk_CALL_RET_STRUCT(_type) \
                if ([typeString rangeOfString:@#_type].location != NSNotFound) {    \
                _type result;   \
                [invocation getReturnValue:&result];\
                NSValue * returnValue = [NSValue valueWithBytes:&(result) objCType:@encode(_type)];\
                return returnValue;\
                }
                                    vk_CALL_RET_STRUCT(CGRect)
                                    vk_CALL_RET_STRUCT(CGPoint)
                                    vk_CALL_RET_STRUCT(CGSize)
                                    vk_CALL_RET_STRUCT(NSRange)
                                    vk_CALL_RET_STRUCT(CGAffineTransform)
                                    vk_CALL_RET_STRUCT(UIEdgeInsets)
                                    vk_CALL_RET_STRUCT(UIOffset)
                                    vk_CALL_RET_STRUCT(CGVector)
                }
                    break;
                case '*':{

                }
                    break;
                case '^': {

                }
                    break;
                case '#': {

                }
                    break;
            }
            return nil;
        }
    }
    return nil;
};

static NSArray *vk_targetBoxingArguments(va_list argList, Class cls, SEL selector, NSError *__autoreleasing *error){

    NSMethodSignature *methodSignature = vk_getMethodSignature(cls, selector);
    NSString *selName = vk_selectorName(selector);

    if (!methodSignature) {
        NSString* errorStr = [NSString stringWithFormat:@"unrecognized selector (%@)", selName];
        vk_generateError(errorStr,error);
        return nil;
    }
    NSMutableArray *argumentsBoxingArray = [[NSMutableArray alloc]init];

    for (NSUInteger i = 2; i < [methodSignature numberOfArguments]; i++) {
        const char *argumentType = [methodSignature getArgumentTypeAtIndex:i];
        switch (argumentType[0] == 'r' ? argumentType[1] : argumentType[0]) {

        #define vk_BOXING_ARG_CASE(_typeString, _type)\
        case _typeString: {\
        _type value = va_arg(argList, _type);\
        [argumentsBoxingArray addObject:@(value)];\
        break; \
        }\

                        vk_BOXING_ARG_CASE('c', int)
                        vk_BOXING_ARG_CASE('C', int)
                        vk_BOXING_ARG_CASE('s', int)
                        vk_BOXING_ARG_CASE('S', int)
                        vk_BOXING_ARG_CASE('i', int)
                        vk_BOXING_ARG_CASE('I', unsigned int)
                        vk_BOXING_ARG_CASE('l', long)
                        vk_BOXING_ARG_CASE('L', unsigned long)
                        vk_BOXING_ARG_CASE('q', long long)
                        vk_BOXING_ARG_CASE('Q', unsigned long long)
                        vk_BOXING_ARG_CASE('f', double)
                        vk_BOXING_ARG_CASE('d', double)
                        vk_BOXING_ARG_CASE('B', int)

            case ':': {
                SEL value = va_arg(argList, SEL);
                NSString *selValueName = NSStringFromSelector(value);
                [argumentsBoxingArray addObject:selValueName];
            }
                break;
            case '{': {
                NSString *typeString = vk_extractStructName([NSString stringWithUTF8String:argumentType]);

            #define vk_FWD_ARG_STRUCT(_type, _methodName) \
            if ([typeString rangeOfString:@#_type].location != NSNotFound) {    \
            _type val = va_arg(argList, _type);\
            NSValue* value = [NSValue _methodName:val];\
            [argumentsBoxingArray addObject:value];  \
            break; \
            }
                            vk_FWD_ARG_STRUCT(CGRect, valueWithCGRect)
                            vk_FWD_ARG_STRUCT(CGPoint, valueWithCGPoint)
                            vk_FWD_ARG_STRUCT(CGSize, valueWithCGSize)
                            vk_FWD_ARG_STRUCT(NSRange, valueWithRange)
                            vk_FWD_ARG_STRUCT(CGAffineTransform, valueWithCGAffineTransform)
                            vk_FWD_ARG_STRUCT(UIEdgeInsets, valueWithUIEdgeInsets)
                            vk_FWD_ARG_STRUCT(UIOffset, valueWithUIOffset)
                            vk_FWD_ARG_STRUCT(CGVector, valueWithCGVector)
            }
                break;
            case '*':{
                vk_generateError(@"unsupported char* argumenst",error);
                return nil;
            }
                break;
            case '^': {
                void *value = va_arg(argList, void**);
                vk_pointer *pointerObj = [[vk_pointer alloc]init];
                pointerObj.pointer = value;
                [argumentsBoxingArray addObject:pointerObj];
            }
                break;
            case '#': {
                Class value = va_arg(argList, Class);
                [argumentsBoxingArray addObject:(id)value];
//                vk_generateError(@"unsupported class argumenst",error);
//                return nil;
            }
                break;
            case '@':{
                id value = va_arg(argList, id);
                if (value) {
                    [argumentsBoxingArray addObject:value];
                }else{
                    [argumentsBoxingArray addObject:[vk_nilObject new]];
                }
            }
                break;
            default: {
                vk_generateError(@"unsupported argumenst",error);
                return nil;
            }
        }
    }
    return [argumentsBoxingArray copy];
}

@implementation NSObject (VKMsgSend)

+ (id)VKCallSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...{

    va_list argList;
    va_start(argList, error);
    SEL selector = NSSelectorFromString(selName);
    NSArray *boxingAruments = vk_targetBoxingArguments(argList, [self class], selector, error);
    va_end(argList);

    if (!boxingAruments) {
        return nil;
    }
    return vk_targetCallSelectorWithArgumentError(self, selector, boxingAruments, error);
}

+ (id)VKCallSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...{

    va_list argList;
    va_start(argList, error);
    NSArray* boxingArguments = vk_targetBoxingArguments(argList, [self class], selector, error);
    va_end(argList);

    if (!boxingArguments) {
        return nil;
    }
    return vk_targetCallSelectorWithArgumentError(self, selector, boxingArguments, error);
}

- (id)VKCallSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...{

    va_list argList;
    va_start(argList, error);
    SEL selector = NSSelectorFromString(selName);
    NSArray* boxingArguments = vk_targetBoxingArguments(argList, [self class], selector, error);
    va_end(argList);

    if (!boxingArguments) {
        return nil;
    }
    return vk_targetCallSelectorWithArgumentError(self, selector, boxingArguments, error);
}

- (id)VKCallSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...{

    va_list argList;
    va_start(argList, error);
    NSArray* boxingArguments = vk_targetBoxingArguments(argList, [self class], selector, error);
    va_end(argList);

    if (!boxingArguments) {
        return nil;
    }

    return vk_targetCallSelectorWithArgumentError(self, selector, boxingArguments, error);
}

@end

@implementation NSString (VKMsgSend)


-(id)VKCallClassSelector:(SEL)selector error:(NSError *__autoreleasing *)error, ...
{
    Class cls = NSClassFromString(self);
    if (!cls) {
        NSString* errorStr = [NSString stringWithFormat:@"unrecognized className (%@)", self];
        vk_generateError(errorStr,error);
        return nil;
    }

    va_list argList;
    va_start(argList, error);
    NSArray* boxingArguments = vk_targetBoxingArguments(argList, cls, selector, error);
    va_end(argList);

    if (!boxingArguments) {
        return nil;
    }

    return vk_targetCallSelectorWithArgumentError(cls, selector, boxingArguments, error);
}


-(id)VKCallClassSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error, ...
{
    Class cls = NSClassFromString(self);
    if (!cls) {
        NSString* errorStr = [NSString stringWithFormat:@"unrecognized className (%@)", self];
        vk_generateError(errorStr,error);
        return nil;
    }

    SEL selector = NSSelectorFromString(selName);

    va_list argList;
    va_start(argList, error);
    NSArray* boxingArguments = vk_targetBoxingArguments(argList, cls, selector, error);
    va_end(argList);

    if (!boxingArguments) {
        return nil;
    }

    return vk_targetCallSelectorWithArgumentError(cls, selector, boxingArguments, error);
}

-(id)VKCallClassAllocInitSelector:(SEL)selector error:(NSError *__autoreleasing *)error, ...
{
    Class cls = NSClassFromString(self);
    if (!cls) {
        NSString* errorStr = [NSString stringWithFormat:@"unrecognized className (%@)", self];
        vk_generateError(errorStr,error);
        return nil;
    }

    va_list argList;
    va_start(argList, error);
    NSArray* boxingArguments = vk_targetBoxingArguments(argList, cls, selector, error);
    va_end(argList);

    if (!boxingArguments) {
        return nil;
    }

    id allocObj = [cls alloc];
    return vk_targetCallSelectorWithArgumentError(allocObj, selector, boxingArguments, error);
}

-(id)VKCallClassAllocInitSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error, ...
{
    Class cls = NSClassFromString(self);
    if (!cls) {
        NSString* errorStr = [NSString stringWithFormat:@"unrecognized className (%@)", self];
        vk_generateError(errorStr,error);
        return nil;
    }

    SEL selector = NSSelectorFromString(selName);

    va_list argList;
    va_start(argList, error);
    NSArray* boxingArguments = vk_targetBoxingArguments(argList, cls, selector, error);
    va_end(argList);

    if (!boxingArguments) {
        return nil;
    }

    id allocObj = [cls alloc];
    return vk_targetCallSelectorWithArgumentError(allocObj, selector, boxingArguments, error);
}

@end

至于怎么使用 。。。。。。。。。

#import "ViewController.h"
#import "VKMsgSend.h"
#import <objc/message.h>
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    Class cls = NSClassFromString(@"testClassA");

    id abc = [[cls alloc]init];

    NSError *err;

    //this warning is ok Selector is in testClassA
    NSString *return1 = [abc VKCallSelector:@selector(testfunction:withB:) error:&err,4,3.5f];
    NSLog(@"%@",return1);

    NSNumber *return3 = [abc VKCallSelectorName:@"testfunction:withB:withC:" error:nil,4,3.5,@"haha"];
    NSInteger tureReturn3 = [return3 integerValue];
    NSLog(@"%@",@(tureReturn3));

    NSString *return4 = [abc VKCallSelectorName:@"testfunction:withB:withC:withD:" error:nil,4,3.5,nil, CGRectMake(10, 10, 10, 10)];
    NSLog(@"%@",return4);

    NSError* testerr2;
    [abc VKCallSelectorName:@"testFunctionError:" error:nil,&testerr2];

    NSLog(@"see more test case in XCTest Target");
    NSLog(@"vk_msgSend_projTests");

    //这是一段展示 performselector 缺点和不足的代码,有注释中文解释
    [self performShow];
    //这是一段展示 objc_msgsend 缺点和不足的代码,有注释和中文解释
    [self msgsendShow];
    //这是对比展示 VKMsgSend的代码
    [self vkshow];
}

-(void)performShow
{

    Class cls = NSClassFromString(@"testClassA");

    id abc = [[cls alloc]init];

    //-(NSString*)testfunction:(int)num withB:(float)boolv
    NSString * result = [abc performSelector:@selector(testfunction:withB:) withObject:@4 withObject:@3.5];
    NSLog(@"%@",result);
    //并且只支持id,如果你敢把基础数值类型封装成number传进去,数值还是错乱的
    //这样代码跑进去  int 传了个NSNumber进去 函数内指针全乱,参数值都飞了

    //3个参数就不支持了,打开注释你会发现,就没有传3个参数的方法
//    [abc performSelector:@selector(testfunction:withB:withC:) withObject:@4.5 withObject:@3 withObject:@"ssss"];
}

-(void)msgsendShow
{
    Class cls = NSClassFromString(@"testClassA");

    id abc = [[cls alloc]init];
//    NSString *result = objc_msgSend(abc, @selector(testfunction:withB:), 4, 3.5);

    //很抱歉上面这样的方法,看着用的很方便,但是在iOS 64位下会直接崩溃,xcode8下是直接无法编译
    NSString *result2 =  ((NSString* (*)(id, SEL, int,float))objc_msgSend)(abc, @selector(testfunction:withB:), 4, 3.5);

    //看到没必须这么费劲的写一坨C语言的函数指针强转才可以

    NSLog(@"%@",result2);
}

-(void)vkshow
{
    //理想状态下 旧的 objc_msgSend就已经很方便了,但是已经不能这么用了,那我就封装出了一个runtime工具
    Class cls = NSClassFromString(@"testClassA");
    id abc = [[cls alloc]init];
    NSError * error;

    //很方便吧
    [abc VKCallSelectorName:@"testfunction:withB:" error:&error,4,3.5];
    //支持所有基础类型,结构体,id类型,class类型,selector类型,block类型,还有指针类型 **

    //如果是使用类方法,还可以直接通过类名NSString
    [@"testClassA" VKCallClassSelectorName:@"testfunction:withB:withH" error:&error,4,3.5,@"aaa"];

    //如果是实例方法,可以直接通过类名NSString,调用init selector,哪怕initWithXX:XX:等自定义的初始化函数都可以
    id abcc = [@"testClassA" VKCallClassAllocInitSelectorName:@"init" error:nil];
    NSLog(@"%@",abcc);
    //省去了手写NSClassFromString 的事情

}

当然,这里附上github地址 https://github.com/Awhisper/VKMsgSend

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
- (void)close { // Empty queues. [self emptyQueues]; [partialReadBuffer release]; partialReadBuffer = nil; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(disconnect) object:nil]; // Close streams. if (theReadStream != NULL) { CFReadStreamSetClient(theReadStream, kCFStreamEventNone, NULL, NULL); CFReadStreamUnscheduleFromRunLoop (theReadStream, theRunLoop, kCFRunLoopDefaultMode); CFReadStreamClose (theReadStream); CFRelease (theReadStream); theReadStream = NULL; } if (theWriteStream != NULL) { CFWriteStreamSetClient(theWriteStream, kCFStreamEventNone, NULL, NULL); CFWriteStreamUnscheduleFromRunLoop (theWriteStream, theRunLoop, kCFRunLoopDefaultMode); CFWriteStreamClose (theWriteStream); CFRelease (theWriteStream); theWriteStream = NULL; } // Close sockets. if (theSocket != NULL) { CFSocketInvalidate (theSocket); CFRelease (theSocket); theSocket = NULL; } if (theSocket6 != NULL) { CFSocketInvalidate (theSocket6); CFRelease (theSocket6); theSocket6 = NULL; } if (theSource != NULL) { CFRunLoopRemoveSource (theRunLoop, theSource, kCFRunLoopDefaultMode); CFRelease (theSource); theSource = NULL; } if (theSource6 != NULL) { CFRunLoopRemoveSource (theRunLoop, theSource6, kCFRunLoopDefaultMode); CFRelease (theSource6); theSource6 = NULL; } theRunLoop = NULL; // If the client has passed the connect/accept method, then the connection has at least begun. // Notify delegate that it is now ending. if (theFlags & kDidPassConnectMethod) { // Delay notification to give him freedom to release without returning here and core-dumping. if ([theDelegate respondsToSelector: @selector(onSocketDidDisconnect:)]) { //[theDelegate performSelector:@selector(onSocketDidDisconnect:) withObject:self afterDelay:0]; [theDelegate onSocketDidDisconnect:self]; } } // Clear flags. theFlags = 0x00; }
06-13

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值