├── README.md ├── VKMsgSend ├── VKMsgSend.h └── VKMsgSend.m ├── VKMsgSend_Proj.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── Awhisper.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── Awhisper.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── VKMsgSend_Proj.xcscheme │ └── xcschememanagement.plist ├── VKMsgSend_Proj ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── ViewController.h ├── ViewController.m ├── main.m ├── testClassA.h └── testClassA.m ├── VKMsgSend_ProjTests ├── Info.plist └── VKMsgSend_ProjTests.m └── VKMsgSend_ProjUITests ├── Info.plist └── VKMsgSend_ProjUITests.m /README.md: -------------------------------------------------------------------------------- 1 | # vk_msgSend 2 | 3 | ## 引子 4 | 写这个工具的初衷,无依赖和引用去调用方法,在OC里面使用起来各种不方便 5 | 6 | - 现有的`NSObject`中的方法`performSelector:withObject:`使用起来不够直接,并且有太多限制 7 | - 使用`runtime`的`objc_msgSend`的方法,在32位时代还算好用,到了64位的时候,调用起来必须强制转换 8 | - 使用`runtime`来获取`Class`,进而获取`Method`,进而获取`Imp`进行直接调用,同`objc_msgSend`一模一样,都必须强制类型转换 9 | - 依赖注入的框架太大太重了,未免杀鸡用牛刀 10 | 11 | ## 功能 12 | 13 | - 可以无需`import`变可直接调用对象的方法 14 | - 可以调用类方法,实例方法 15 | - 可以支持`int`,`float`,`NSInteger`,`CGFloat`,等基础类型 16 | - 可以支持`CGSize`,`CGRect`,`CGPoint`,等8个系统结构体 17 | - 可以支持任意`id`类型 18 | 19 | ## 使用 20 | ### 对一个对象调用一个实例方法 21 | 既然目的是不想`import`文件,首先要有一个对象嘛 22 | 23 | ```objc 24 | Class cls = NSClassFromString(@"testClassA"); 25 | id abc = [[cls alloc]init]; 26 | ``` 27 | 28 | 有了对象就可以最简单的使用了,这个`testClassA`有一个方法 29 | 30 | ```objc 31 | -(NSString*)testfunction:(int)num withB:(float)boolv 32 | ``` 33 | 34 | 使用方法 35 | 36 | ```objc 37 | NSString *return = [abc vk_callSelector:@selector(testfunction:withB:) error:&err,4,3.5f]; 38 | ``` 39 | 40 | 使用起来很简单是不?让id类对象声明遵从``协议,便可以放心大胆的调用,传入`selector`,传入一个`error`错误信息指针,后面直接是可变参数设计,直接塞入所需要的参数就可以了 41 | 42 | ### 对一个类调用一个类方法 43 | 直接将类,转成遵从``协议的id,即可调用 44 | 45 | ```objc 46 | Class cls = NSClassFromString(@"testClassA"); 47 | [(id)cls vk_callSelector:@selector(testfunction:withB:withH:) error:nil,4,3.5,@"haha"]; 48 | ``` 49 | 50 | ### 返回值Notes 51 | 如果原函数返回值是基础类型`int`,`float`,`NSInteger`,`CGFloat`等,或者`CGSize`,`CGRect`,`CGPoint`等结构体,返回的数值会被封装成`NSValue`或者`NSNumber`,此处还没找到更好的处理办法 52 | 53 | 方法例子: 54 | 55 | ```objc 56 | -(NSInteger)testfunction:(int)num withB:(float)boolv withC:(NSString*)str 57 | -(CGRect)testfunction:(int)num withB:(float)boolv withC:(NSString*)str withE:(NSRange)rect 58 | ``` 59 | 60 | 调用例子: 61 | 第一个方法 62 | 63 | ```objc 64 | NSNumber *return3 = [abc vk_callSelectorName:@"testfunction:withB:withC:" error:&err,4,3.5,@"haha"]; 65 | NSInteger tureReturn3 = [return3 integerValue]; 66 | // need intValue 67 | ``` 68 | 69 | 第二个方法 70 | 71 | ```objc 72 | NSValue *return5 = [abc vk_callSelector:@selector(testfunction:withB:withC:withE:) error:nil,4,3.5,@"haha", NSMakeRange(1, 3)]; 73 | CGRect trueReturn5 = [return5 CGRectValue]; 74 | //need CGRectValue 75 | ``` 76 | 77 | 78 | 之所以需要额外写的原因,是因为声明函数的时候,返回值不知道如何通用匹配。 79 | 80 | 参数之所以可以通用匹配是因为使用了可变参数。 81 | 82 | 不知道有没有更好的办法。 83 | ### 其他方法 84 | 其实不仅支持输入SEL,直接输入string型的,具体参见Demo里面的测试用例 85 | 86 | ```objc 87 | + (id)vk_callSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...; 88 | + (id)vk_callSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...; 89 | - (id)vk_callSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...; 90 | - (id)vk_callSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...; 91 | ``` 92 | 93 | 94 | ## 对比 95 | - performSelector缺点 96 | - 参数限制,performSelector只支持id 97 | - 参数个数,performSelector在NSObject里系统最多只支持4个参数 98 | - 用法,每加一个参数必须多写一个`withObject`,过于麻烦 99 | - objc_msgSend缺点 100 | - 32Bit下使用起来非常方便 101 | - 64Bit下由于系统底层传参方案改动非常大,因此强制要求进行参数类型,返回类型的函数类型转换,如果不进行类型转换,像32Bit那样直接调用就会crash 102 | - 每一次调用都,手写调用函数的类型转换,也是挺麻烦的 103 | - runtime的`Imp`调用缺点 104 | - `Imp`和`objc_msgSend`其实是同一个原因,二者本是一个意思 105 | 106 | 107 | 108 | ## 补充 109 | `block`,`id *`,`SEL`都支持完毕 110 | 111 | 但是 id* 我有点心虚,求code review 112 | 113 | `Class` 也支持完毕 114 | -------------------------------------------------------------------------------- /VKMsgSend/VKMsgSend.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+idSelectorCall.h 3 | // IdSelectorCall 4 | // 5 | // Created by Awhisper on 15/12/25. 6 | // Copyright © 2015年 Awhisper. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface NSObject (VKMsgSend) 13 | 14 | + (id)VKCallSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...; 15 | 16 | + (id)VKCallSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...; 17 | 18 | - (id)VKCallSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...; 19 | 20 | - (id)VKCallSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...; 21 | 22 | @end 23 | 24 | @interface NSString (VKMsgSend) 25 | 26 | - (id)VKCallClassSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...; 27 | 28 | - (id)VKCallClassSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...; 29 | 30 | - (id)VKCallClassAllocInitSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...; 31 | 32 | - (id)VKCallClassAllocInitSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /VKMsgSend/VKMsgSend.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+idSelectorCall.m 3 | // IdSelectorCall 4 | // 5 | // Created by Awhisper on 15/12/25. 6 | // Copyright © 2015年 Awhisper. All rights reserved. 7 | // 8 | 9 | #import "VKMsgSend.h" 10 | 11 | #if TARGET_OS_IPHONE 12 | #import 13 | #endif 14 | 15 | 16 | #pragma mark : vk_nilObject 17 | 18 | @interface vk_pointer : NSObject 19 | 20 | @property (nonatomic) void *pointer; 21 | 22 | @end 23 | 24 | @implementation vk_pointer 25 | 26 | @end 27 | 28 | @interface vk_nilObject : NSObject 29 | 30 | @end 31 | 32 | @implementation vk_nilObject 33 | 34 | @end 35 | 36 | #pragma mark : static 37 | 38 | static NSLock *_vkMethodSignatureLock; 39 | static NSMutableDictionary *_vkMethodSignatureCache; 40 | static vk_nilObject *vknilPointer = nil; 41 | 42 | static NSString *vk_extractStructName(NSString *typeEncodeString){ 43 | 44 | NSArray *array = [typeEncodeString componentsSeparatedByString:@"="]; 45 | NSString *typeString = array[0]; 46 | __block int firstVaildIndex = 0; 47 | [array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 48 | unichar c = [typeEncodeString characterAtIndex:idx]; 49 | if (c=='{'||c=='_') { 50 | firstVaildIndex++; 51 | }else{ 52 | *stop = YES; 53 | } 54 | }]; 55 | return [typeString substringFromIndex:firstVaildIndex]; 56 | } 57 | 58 | static NSString *vk_selectorName(SEL selector){ 59 | const char *selNameCstr = sel_getName(selector); 60 | NSString *selName = [[NSString alloc]initWithUTF8String:selNameCstr]; 61 | return selName; 62 | } 63 | 64 | static NSMethodSignature *vk_getMethodSignature(Class cls, SEL selector){ 65 | 66 | if (!_vkMethodSignatureLock) { 67 | _vkMethodSignatureLock = [[NSLock alloc] init]; 68 | } 69 | 70 | [_vkMethodSignatureLock lock]; 71 | 72 | if (!_vkMethodSignatureCache) { 73 | _vkMethodSignatureCache = [[NSMutableDictionary alloc]init]; 74 | } 75 | if (!_vkMethodSignatureCache[cls]) { 76 | _vkMethodSignatureCache[(id)cls] =[[NSMutableDictionary alloc]init]; 77 | } 78 | NSString *selName = vk_selectorName(selector); 79 | NSMethodSignature *methodSignature = _vkMethodSignatureCache[cls][selName]; 80 | if (!methodSignature) { 81 | methodSignature = [cls instanceMethodSignatureForSelector:selector]; 82 | if (methodSignature) { 83 | _vkMethodSignatureCache[cls][selName] = methodSignature; 84 | }else 85 | { 86 | methodSignature = [cls methodSignatureForSelector:selector]; 87 | if (methodSignature) { 88 | _vkMethodSignatureCache[cls][selName] = methodSignature; 89 | } 90 | } 91 | } 92 | [_vkMethodSignatureLock unlock]; 93 | return methodSignature; 94 | } 95 | 96 | static void vk_generateError(NSString *errorInfo, NSError **error){ 97 | if (error) { 98 | *error = [NSError errorWithDomain:errorInfo code:0 userInfo:nil]; 99 | } 100 | } 101 | 102 | static id vk_targetCallSelectorWithArgumentError(id target, SEL selector, NSArray *argsArr, NSError *__autoreleasing *error){ 103 | 104 | Class cls = [target class]; 105 | NSMethodSignature *methodSignature = vk_getMethodSignature(cls, selector); 106 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; 107 | [invocation setTarget:target]; 108 | [invocation setSelector:selector]; 109 | 110 | NSMutableArray* _markArray; 111 | 112 | for (NSUInteger i = 2; i< [methodSignature numberOfArguments]; i++) { 113 | const char *argumentType = [methodSignature getArgumentTypeAtIndex:i]; 114 | id valObj = argsArr[i-2]; 115 | switch (argumentType[0]=='r'?argumentType[1]:argumentType[0]) { 116 | #define VK_CALL_ARG_CASE(_typeString, _type, _selector) \ 117 | case _typeString: { \ 118 | _type value = [valObj _selector]; \ 119 | [invocation setArgument:&value atIndex:i];\ 120 | break; \ 121 | } 122 | VK_CALL_ARG_CASE('c', char, charValue) 123 | VK_CALL_ARG_CASE('C', unsigned char, unsignedCharValue) 124 | VK_CALL_ARG_CASE('s', short, shortValue) 125 | VK_CALL_ARG_CASE('S', unsigned short, unsignedShortValue) 126 | VK_CALL_ARG_CASE('i', int, intValue) 127 | VK_CALL_ARG_CASE('I', unsigned int, unsignedIntValue) 128 | VK_CALL_ARG_CASE('l', long, longValue) 129 | VK_CALL_ARG_CASE('L', unsigned long, unsignedLongValue) 130 | VK_CALL_ARG_CASE('q', long long, longLongValue) 131 | VK_CALL_ARG_CASE('Q', unsigned long long, unsignedLongLongValue) 132 | VK_CALL_ARG_CASE('f', float, floatValue) 133 | VK_CALL_ARG_CASE('d', double, doubleValue) 134 | VK_CALL_ARG_CASE('B', BOOL, boolValue) 135 | 136 | case ':':{ 137 | NSString *selName = valObj; 138 | SEL selValue = NSSelectorFromString(selName); 139 | [invocation setArgument:&selValue atIndex:i]; 140 | } 141 | break; 142 | case '{':{ 143 | NSString *typeString = vk_extractStructName([NSString stringWithUTF8String:argumentType]); 144 | NSValue *val = (NSValue *)valObj; 145 | #define vk_CALL_ARG_STRUCT(_type, _methodName) \ 146 | if ([typeString rangeOfString:@#_type].location != NSNotFound) { \ 147 | _type value = [val _methodName]; \ 148 | [invocation setArgument:&value atIndex:i]; \ 149 | break; \ 150 | } 151 | vk_CALL_ARG_STRUCT(CGRect, CGRectValue) 152 | vk_CALL_ARG_STRUCT(CGPoint, CGPointValue) 153 | vk_CALL_ARG_STRUCT(CGSize, CGSizeValue) 154 | vk_CALL_ARG_STRUCT(NSRange, rangeValue) 155 | vk_CALL_ARG_STRUCT(CGAffineTransform, CGAffineTransformValue) 156 | vk_CALL_ARG_STRUCT(UIEdgeInsets, UIEdgeInsetsValue) 157 | vk_CALL_ARG_STRUCT(UIOffset, UIOffsetValue) 158 | vk_CALL_ARG_STRUCT(CGVector, CGVectorValue) 159 | } 160 | break; 161 | case '*':{ 162 | NSCAssert(NO, @"argument boxing wrong,char* is not supported"); 163 | } 164 | break; 165 | case '^':{ 166 | if ([valObj isKindOfClass:[vk_nilObject class]]) { 167 | [invocation setArgument:&vknilPointer atIndex:i]; 168 | }else{ 169 | vk_pointer *value = valObj; 170 | void *pointer = value.pointer; 171 | id obj = *((__unsafe_unretained id *)pointer); 172 | if (!obj) { 173 | if (argumentType[1] == '@') { 174 | if (!_markArray) { 175 | _markArray = [[NSMutableArray alloc] init]; 176 | } 177 | [_markArray addObject:valObj]; 178 | } 179 | } 180 | [invocation setArgument:&pointer atIndex:i]; 181 | } 182 | } 183 | break; 184 | case '#':{ 185 | [invocation setArgument:&valObj atIndex:i]; 186 | } 187 | break; 188 | default:{ 189 | if ([valObj isKindOfClass:[vk_nilObject class]]) { 190 | [invocation setArgument:&vknilPointer atIndex:i]; 191 | }else{ 192 | [invocation setArgument:&valObj atIndex:i]; 193 | } 194 | } 195 | } 196 | } 197 | 198 | [invocation invoke]; 199 | 200 | if ([_markArray count] > 0) { 201 | for (vk_pointer *pointerObj in _markArray) { 202 | void *pointer = pointerObj.pointer; 203 | id obj = *((__unsafe_unretained id *)pointer); 204 | if (obj) { 205 | CFRetain((__bridge CFTypeRef)(obj)); 206 | } 207 | } 208 | } 209 | 210 | const char *returnType = [methodSignature methodReturnType]; 211 | NSString *selName = vk_selectorName(selector); 212 | if (strncmp(returnType, "v", 1) != 0 ) { 213 | if (strncmp(returnType, "@", 1) == 0) { 214 | void *result; 215 | [invocation getReturnValue:&result]; 216 | 217 | if (result == NULL) { 218 | return nil; 219 | } 220 | 221 | id returnValue; 222 | if ([selName isEqualToString:@"alloc"] || [selName isEqualToString:@"new"] || [selName isEqualToString:@"copy"] || [selName isEqualToString:@"mutableCopy"]) { 223 | returnValue = (__bridge_transfer id)result; 224 | }else{ 225 | returnValue = (__bridge id)result; 226 | } 227 | return returnValue; 228 | 229 | } else { 230 | switch (returnType[0] == 'r' ? returnType[1] : returnType[0]) { 231 | 232 | #define vk_CALL_RET_CASE(_typeString, _type) \ 233 | case _typeString: { \ 234 | _type returnValue; \ 235 | [invocation getReturnValue:&returnValue];\ 236 | return @(returnValue); \ 237 | break; \ 238 | } 239 | vk_CALL_RET_CASE('c', char) 240 | vk_CALL_RET_CASE('C', unsigned char) 241 | vk_CALL_RET_CASE('s', short) 242 | vk_CALL_RET_CASE('S', unsigned short) 243 | vk_CALL_RET_CASE('i', int) 244 | vk_CALL_RET_CASE('I', unsigned int) 245 | vk_CALL_RET_CASE('l', long) 246 | vk_CALL_RET_CASE('L', unsigned long) 247 | vk_CALL_RET_CASE('q', long long) 248 | vk_CALL_RET_CASE('Q', unsigned long long) 249 | vk_CALL_RET_CASE('f', float) 250 | vk_CALL_RET_CASE('d', double) 251 | vk_CALL_RET_CASE('B', BOOL) 252 | 253 | case '{': { 254 | NSString *typeString = vk_extractStructName([NSString stringWithUTF8String:returnType]); 255 | #define vk_CALL_RET_STRUCT(_type) \ 256 | if ([typeString rangeOfString:@#_type].location != NSNotFound) { \ 257 | _type result; \ 258 | [invocation getReturnValue:&result];\ 259 | NSValue * returnValue = [NSValue valueWithBytes:&(result) objCType:@encode(_type)];\ 260 | return returnValue;\ 261 | } 262 | vk_CALL_RET_STRUCT(CGRect) 263 | vk_CALL_RET_STRUCT(CGPoint) 264 | vk_CALL_RET_STRUCT(CGSize) 265 | vk_CALL_RET_STRUCT(NSRange) 266 | vk_CALL_RET_STRUCT(CGAffineTransform) 267 | vk_CALL_RET_STRUCT(UIEdgeInsets) 268 | vk_CALL_RET_STRUCT(UIOffset) 269 | vk_CALL_RET_STRUCT(CGVector) 270 | } 271 | break; 272 | case '*':{ 273 | 274 | } 275 | break; 276 | case '^': { 277 | 278 | } 279 | break; 280 | case '#': { 281 | 282 | } 283 | break; 284 | } 285 | return nil; 286 | } 287 | } 288 | return nil; 289 | }; 290 | 291 | static NSArray *vk_targetBoxingArguments(va_list argList, Class cls, SEL selector, NSError *__autoreleasing *error){ 292 | 293 | NSMethodSignature *methodSignature = vk_getMethodSignature(cls, selector); 294 | NSString *selName = vk_selectorName(selector); 295 | 296 | if (!methodSignature) { 297 | NSString* errorStr = [NSString stringWithFormat:@"unrecognized selector (%@)", selName]; 298 | vk_generateError(errorStr,error); 299 | return nil; 300 | } 301 | NSMutableArray *argumentsBoxingArray = [[NSMutableArray alloc]init]; 302 | 303 | for (NSUInteger i = 2; i < [methodSignature numberOfArguments]; i++) { 304 | const char *argumentType = [methodSignature getArgumentTypeAtIndex:i]; 305 | switch (argumentType[0] == 'r' ? argumentType[1] : argumentType[0]) { 306 | 307 | #define vk_BOXING_ARG_CASE(_typeString, _type)\ 308 | case _typeString: {\ 309 | _type value = va_arg(argList, _type);\ 310 | [argumentsBoxingArray addObject:@(value)];\ 311 | break; \ 312 | }\ 313 | 314 | vk_BOXING_ARG_CASE('c', int) 315 | vk_BOXING_ARG_CASE('C', int) 316 | vk_BOXING_ARG_CASE('s', int) 317 | vk_BOXING_ARG_CASE('S', int) 318 | vk_BOXING_ARG_CASE('i', int) 319 | vk_BOXING_ARG_CASE('I', unsigned int) 320 | vk_BOXING_ARG_CASE('l', long) 321 | vk_BOXING_ARG_CASE('L', unsigned long) 322 | vk_BOXING_ARG_CASE('q', long long) 323 | vk_BOXING_ARG_CASE('Q', unsigned long long) 324 | vk_BOXING_ARG_CASE('f', double) 325 | vk_BOXING_ARG_CASE('d', double) 326 | vk_BOXING_ARG_CASE('B', int) 327 | 328 | case ':': { 329 | SEL value = va_arg(argList, SEL); 330 | NSString *selValueName = NSStringFromSelector(value); 331 | [argumentsBoxingArray addObject:selValueName]; 332 | } 333 | break; 334 | case '{': { 335 | NSString *typeString = vk_extractStructName([NSString stringWithUTF8String:argumentType]); 336 | 337 | #define vk_FWD_ARG_STRUCT(_type, _methodName) \ 338 | if ([typeString rangeOfString:@#_type].location != NSNotFound) { \ 339 | _type val = va_arg(argList, _type);\ 340 | NSValue* value = [NSValue _methodName:val];\ 341 | [argumentsBoxingArray addObject:value]; \ 342 | break; \ 343 | } 344 | vk_FWD_ARG_STRUCT(CGRect, valueWithCGRect) 345 | vk_FWD_ARG_STRUCT(CGPoint, valueWithCGPoint) 346 | vk_FWD_ARG_STRUCT(CGSize, valueWithCGSize) 347 | vk_FWD_ARG_STRUCT(NSRange, valueWithRange) 348 | vk_FWD_ARG_STRUCT(CGAffineTransform, valueWithCGAffineTransform) 349 | vk_FWD_ARG_STRUCT(UIEdgeInsets, valueWithUIEdgeInsets) 350 | vk_FWD_ARG_STRUCT(UIOffset, valueWithUIOffset) 351 | vk_FWD_ARG_STRUCT(CGVector, valueWithCGVector) 352 | } 353 | break; 354 | case '*':{ 355 | vk_generateError(@"unsupported char* argumenst",error); 356 | return nil; 357 | } 358 | break; 359 | case '^': { 360 | void *value = va_arg(argList, void**); 361 | if (!value) { 362 | [argumentsBoxingArray addObject:[vk_nilObject new]]; 363 | }else{ 364 | vk_pointer *pointerObj = [[vk_pointer alloc]init]; 365 | pointerObj.pointer = value; 366 | [argumentsBoxingArray addObject:pointerObj]; 367 | } 368 | } 369 | break; 370 | case '#': { 371 | Class value = va_arg(argList, Class); 372 | [argumentsBoxingArray addObject:(id)value]; 373 | // vk_generateError(@"unsupported class argumenst",error); 374 | // return nil; 375 | } 376 | break; 377 | case '@':{ 378 | id value = va_arg(argList, id); 379 | if (value) { 380 | [argumentsBoxingArray addObject:value]; 381 | }else{ 382 | [argumentsBoxingArray addObject:[vk_nilObject new]]; 383 | } 384 | } 385 | break; 386 | default: { 387 | vk_generateError(@"unsupported argumenst",error); 388 | return nil; 389 | } 390 | } 391 | } 392 | return [argumentsBoxingArray copy]; 393 | } 394 | 395 | @implementation NSObject (VKMsgSend) 396 | 397 | + (id)VKCallSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...{ 398 | 399 | va_list argList; 400 | va_start(argList, error); 401 | SEL selector = NSSelectorFromString(selName); 402 | NSArray *boxingAruments = vk_targetBoxingArguments(argList, [self class], selector, error); 403 | va_end(argList); 404 | 405 | if (!boxingAruments) { 406 | return nil; 407 | } 408 | return vk_targetCallSelectorWithArgumentError(self, selector, boxingAruments, error); 409 | } 410 | 411 | + (id)VKCallSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...{ 412 | 413 | va_list argList; 414 | va_start(argList, error); 415 | NSArray* boxingArguments = vk_targetBoxingArguments(argList, [self class], selector, error); 416 | va_end(argList); 417 | 418 | if (!boxingArguments) { 419 | return nil; 420 | } 421 | return vk_targetCallSelectorWithArgumentError(self, selector, boxingArguments, error); 422 | } 423 | 424 | - (id)VKCallSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error,...{ 425 | 426 | va_list argList; 427 | va_start(argList, error); 428 | SEL selector = NSSelectorFromString(selName); 429 | NSArray* boxingArguments = vk_targetBoxingArguments(argList, [self class], selector, error); 430 | va_end(argList); 431 | 432 | if (!boxingArguments) { 433 | return nil; 434 | } 435 | return vk_targetCallSelectorWithArgumentError(self, selector, boxingArguments, error); 436 | } 437 | 438 | - (id)VKCallSelector:(SEL)selector error:(NSError *__autoreleasing *)error,...{ 439 | 440 | va_list argList; 441 | va_start(argList, error); 442 | NSArray* boxingArguments = vk_targetBoxingArguments(argList, [self class], selector, error); 443 | va_end(argList); 444 | 445 | if (!boxingArguments) { 446 | return nil; 447 | } 448 | 449 | return vk_targetCallSelectorWithArgumentError(self, selector, boxingArguments, error); 450 | } 451 | 452 | @end 453 | 454 | @implementation NSString (VKMsgSend) 455 | 456 | 457 | -(id)VKCallClassSelector:(SEL)selector error:(NSError *__autoreleasing *)error, ... 458 | { 459 | Class cls = NSClassFromString(self); 460 | if (!cls) { 461 | NSString* errorStr = [NSString stringWithFormat:@"unrecognized className (%@)", self]; 462 | vk_generateError(errorStr,error); 463 | return nil; 464 | } 465 | 466 | va_list argList; 467 | va_start(argList, error); 468 | NSArray* boxingArguments = vk_targetBoxingArguments(argList, cls, selector, error); 469 | va_end(argList); 470 | 471 | if (!boxingArguments) { 472 | return nil; 473 | } 474 | 475 | return vk_targetCallSelectorWithArgumentError(cls, selector, boxingArguments, error); 476 | } 477 | 478 | 479 | -(id)VKCallClassSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error, ... 480 | { 481 | Class cls = NSClassFromString(self); 482 | if (!cls) { 483 | NSString* errorStr = [NSString stringWithFormat:@"unrecognized className (%@)", self]; 484 | vk_generateError(errorStr,error); 485 | return nil; 486 | } 487 | 488 | SEL selector = NSSelectorFromString(selName); 489 | 490 | va_list argList; 491 | va_start(argList, error); 492 | NSArray* boxingArguments = vk_targetBoxingArguments(argList, cls, selector, error); 493 | va_end(argList); 494 | 495 | if (!boxingArguments) { 496 | return nil; 497 | } 498 | 499 | return vk_targetCallSelectorWithArgumentError(cls, selector, boxingArguments, error); 500 | } 501 | 502 | -(id)VKCallClassAllocInitSelector:(SEL)selector error:(NSError *__autoreleasing *)error, ... 503 | { 504 | Class cls = NSClassFromString(self); 505 | if (!cls) { 506 | NSString* errorStr = [NSString stringWithFormat:@"unrecognized className (%@)", self]; 507 | vk_generateError(errorStr,error); 508 | return nil; 509 | } 510 | 511 | va_list argList; 512 | va_start(argList, error); 513 | NSArray* boxingArguments = vk_targetBoxingArguments(argList, cls, selector, error); 514 | va_end(argList); 515 | 516 | if (!boxingArguments) { 517 | return nil; 518 | } 519 | 520 | id allocObj = [cls alloc]; 521 | return vk_targetCallSelectorWithArgumentError(allocObj, selector, boxingArguments, error); 522 | } 523 | 524 | -(id)VKCallClassAllocInitSelectorName:(NSString *)selName error:(NSError *__autoreleasing *)error, ... 525 | { 526 | Class cls = NSClassFromString(self); 527 | if (!cls) { 528 | NSString* errorStr = [NSString stringWithFormat:@"unrecognized className (%@)", self]; 529 | vk_generateError(errorStr,error); 530 | return nil; 531 | } 532 | 533 | SEL selector = NSSelectorFromString(selName); 534 | 535 | va_list argList; 536 | va_start(argList, error); 537 | NSArray* boxingArguments = vk_targetBoxingArguments(argList, cls, selector, error); 538 | va_end(argList); 539 | 540 | if (!boxingArguments) { 541 | return nil; 542 | } 543 | 544 | id allocObj = [cls alloc]; 545 | return vk_targetCallSelectorWithArgumentError(allocObj, selector, boxingArguments, error); 546 | } 547 | 548 | @end 549 | 550 | -------------------------------------------------------------------------------- /VKMsgSend_Proj.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6CB983A71C97E54A0057AB1C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CB983A61C97E54A0057AB1C /* main.m */; }; 11 | 6CB983AA1C97E54A0057AB1C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CB983A91C97E54A0057AB1C /* AppDelegate.m */; }; 12 | 6CB983AD1C97E54A0057AB1C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CB983AC1C97E54A0057AB1C /* ViewController.m */; }; 13 | 6CB983B01C97E54A0057AB1C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CB983AE1C97E54A0057AB1C /* Main.storyboard */; }; 14 | 6CB983B21C97E54A0057AB1C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CB983B11C97E54A0057AB1C /* Assets.xcassets */; }; 15 | 6CB983B51C97E54A0057AB1C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CB983B31C97E54A0057AB1C /* LaunchScreen.storyboard */; }; 16 | 6CB983C01C97E54A0057AB1C /* VKMsgSend_ProjTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CB983BF1C97E54A0057AB1C /* VKMsgSend_ProjTests.m */; }; 17 | 6CB983CB1C97E54A0057AB1C /* VKMsgSend_ProjUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CB983CA1C97E54A0057AB1C /* VKMsgSend_ProjUITests.m */; }; 18 | 6CB983E01C97E62A0057AB1C /* VKMsgSend.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CB983DE1C97E62A0057AB1C /* VKMsgSend.m */; }; 19 | 6CB983E31C97E6CA0057AB1C /* testClassA.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CB983E21C97E6CA0057AB1C /* testClassA.m */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXContainerItemProxy section */ 23 | 6CB983BC1C97E54A0057AB1C /* PBXContainerItemProxy */ = { 24 | isa = PBXContainerItemProxy; 25 | containerPortal = 6CB9839A1C97E54A0057AB1C /* Project object */; 26 | proxyType = 1; 27 | remoteGlobalIDString = 6CB983A11C97E54A0057AB1C; 28 | remoteInfo = VKMsgSend_Proj; 29 | }; 30 | 6CB983C71C97E54A0057AB1C /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 6CB9839A1C97E54A0057AB1C /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 6CB983A11C97E54A0057AB1C; 35 | remoteInfo = VKMsgSend_Proj; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 6CB983A21C97E54A0057AB1C /* VKMsgSend_Proj.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VKMsgSend_Proj.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 6CB983A61C97E54A0057AB1C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 42 | 6CB983A81C97E54A0057AB1C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 43 | 6CB983A91C97E54A0057AB1C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 44 | 6CB983AB1C97E54A0057AB1C /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 45 | 6CB983AC1C97E54A0057AB1C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 46 | 6CB983AF1C97E54A0057AB1C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 47 | 6CB983B11C97E54A0057AB1C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 48 | 6CB983B41C97E54A0057AB1C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 49 | 6CB983B61C97E54A0057AB1C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | 6CB983BB1C97E54A0057AB1C /* VKMsgSend_ProjTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VKMsgSend_ProjTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 6CB983BF1C97E54A0057AB1C /* VKMsgSend_ProjTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VKMsgSend_ProjTests.m; sourceTree = ""; }; 52 | 6CB983C11C97E54A0057AB1C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | 6CB983C61C97E54A0057AB1C /* VKMsgSend_ProjUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VKMsgSend_ProjUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | 6CB983CA1C97E54A0057AB1C /* VKMsgSend_ProjUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VKMsgSend_ProjUITests.m; sourceTree = ""; }; 55 | 6CB983CC1C97E54A0057AB1C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | 6CB983DD1C97E62A0057AB1C /* VKMsgSend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VKMsgSend.h; sourceTree = ""; }; 57 | 6CB983DE1C97E62A0057AB1C /* VKMsgSend.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VKMsgSend.m; sourceTree = ""; }; 58 | 6CB983E11C97E6CA0057AB1C /* testClassA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testClassA.h; sourceTree = ""; }; 59 | 6CB983E21C97E6CA0057AB1C /* testClassA.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = testClassA.m; sourceTree = ""; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | 6CB9839F1C97E54A0057AB1C /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | 6CB983B81C97E54A0057AB1C /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | 6CB983C31C97E54A0057AB1C /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | /* End PBXFrameworksBuildPhase section */ 85 | 86 | /* Begin PBXGroup section */ 87 | 6CB983991C97E54A0057AB1C = { 88 | isa = PBXGroup; 89 | children = ( 90 | 6CB983D81C97E56D0057AB1C /* VKMsgSend */, 91 | 6CB983A41C97E54A0057AB1C /* VKMsgSend_Proj */, 92 | 6CB983BE1C97E54A0057AB1C /* VKMsgSend_ProjTests */, 93 | 6CB983C91C97E54A0057AB1C /* VKMsgSend_ProjUITests */, 94 | 6CB983A31C97E54A0057AB1C /* Products */, 95 | ); 96 | sourceTree = ""; 97 | }; 98 | 6CB983A31C97E54A0057AB1C /* Products */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 6CB983A21C97E54A0057AB1C /* VKMsgSend_Proj.app */, 102 | 6CB983BB1C97E54A0057AB1C /* VKMsgSend_ProjTests.xctest */, 103 | 6CB983C61C97E54A0057AB1C /* VKMsgSend_ProjUITests.xctest */, 104 | ); 105 | name = Products; 106 | sourceTree = ""; 107 | }; 108 | 6CB983A41C97E54A0057AB1C /* VKMsgSend_Proj */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 6CB983E11C97E6CA0057AB1C /* testClassA.h */, 112 | 6CB983E21C97E6CA0057AB1C /* testClassA.m */, 113 | 6CB983A81C97E54A0057AB1C /* AppDelegate.h */, 114 | 6CB983A91C97E54A0057AB1C /* AppDelegate.m */, 115 | 6CB983AB1C97E54A0057AB1C /* ViewController.h */, 116 | 6CB983AC1C97E54A0057AB1C /* ViewController.m */, 117 | 6CB983AE1C97E54A0057AB1C /* Main.storyboard */, 118 | 6CB983B11C97E54A0057AB1C /* Assets.xcassets */, 119 | 6CB983B31C97E54A0057AB1C /* LaunchScreen.storyboard */, 120 | 6CB983B61C97E54A0057AB1C /* Info.plist */, 121 | 6CB983A51C97E54A0057AB1C /* Supporting Files */, 122 | ); 123 | path = VKMsgSend_Proj; 124 | sourceTree = ""; 125 | }; 126 | 6CB983A51C97E54A0057AB1C /* Supporting Files */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 6CB983A61C97E54A0057AB1C /* main.m */, 130 | ); 131 | name = "Supporting Files"; 132 | sourceTree = ""; 133 | }; 134 | 6CB983BE1C97E54A0057AB1C /* VKMsgSend_ProjTests */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 6CB983BF1C97E54A0057AB1C /* VKMsgSend_ProjTests.m */, 138 | 6CB983C11C97E54A0057AB1C /* Info.plist */, 139 | ); 140 | path = VKMsgSend_ProjTests; 141 | sourceTree = ""; 142 | }; 143 | 6CB983C91C97E54A0057AB1C /* VKMsgSend_ProjUITests */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 6CB983CA1C97E54A0057AB1C /* VKMsgSend_ProjUITests.m */, 147 | 6CB983CC1C97E54A0057AB1C /* Info.plist */, 148 | ); 149 | path = VKMsgSend_ProjUITests; 150 | sourceTree = ""; 151 | }; 152 | 6CB983D81C97E56D0057AB1C /* VKMsgSend */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 6CB983DD1C97E62A0057AB1C /* VKMsgSend.h */, 156 | 6CB983DE1C97E62A0057AB1C /* VKMsgSend.m */, 157 | ); 158 | path = VKMsgSend; 159 | sourceTree = ""; 160 | }; 161 | /* End PBXGroup section */ 162 | 163 | /* Begin PBXNativeTarget section */ 164 | 6CB983A11C97E54A0057AB1C /* VKMsgSend_Proj */ = { 165 | isa = PBXNativeTarget; 166 | buildConfigurationList = 6CB983CF1C97E54A0057AB1C /* Build configuration list for PBXNativeTarget "VKMsgSend_Proj" */; 167 | buildPhases = ( 168 | 6CB9839E1C97E54A0057AB1C /* Sources */, 169 | 6CB9839F1C97E54A0057AB1C /* Frameworks */, 170 | 6CB983A01C97E54A0057AB1C /* Resources */, 171 | ); 172 | buildRules = ( 173 | ); 174 | dependencies = ( 175 | ); 176 | name = VKMsgSend_Proj; 177 | productName = VKMsgSend_Proj; 178 | productReference = 6CB983A21C97E54A0057AB1C /* VKMsgSend_Proj.app */; 179 | productType = "com.apple.product-type.application"; 180 | }; 181 | 6CB983BA1C97E54A0057AB1C /* VKMsgSend_ProjTests */ = { 182 | isa = PBXNativeTarget; 183 | buildConfigurationList = 6CB983D21C97E54A0057AB1C /* Build configuration list for PBXNativeTarget "VKMsgSend_ProjTests" */; 184 | buildPhases = ( 185 | 6CB983B71C97E54A0057AB1C /* Sources */, 186 | 6CB983B81C97E54A0057AB1C /* Frameworks */, 187 | 6CB983B91C97E54A0057AB1C /* Resources */, 188 | ); 189 | buildRules = ( 190 | ); 191 | dependencies = ( 192 | 6CB983BD1C97E54A0057AB1C /* PBXTargetDependency */, 193 | ); 194 | name = VKMsgSend_ProjTests; 195 | productName = VKMsgSend_ProjTests; 196 | productReference = 6CB983BB1C97E54A0057AB1C /* VKMsgSend_ProjTests.xctest */; 197 | productType = "com.apple.product-type.bundle.unit-test"; 198 | }; 199 | 6CB983C51C97E54A0057AB1C /* VKMsgSend_ProjUITests */ = { 200 | isa = PBXNativeTarget; 201 | buildConfigurationList = 6CB983D51C97E54A0057AB1C /* Build configuration list for PBXNativeTarget "VKMsgSend_ProjUITests" */; 202 | buildPhases = ( 203 | 6CB983C21C97E54A0057AB1C /* Sources */, 204 | 6CB983C31C97E54A0057AB1C /* Frameworks */, 205 | 6CB983C41C97E54A0057AB1C /* Resources */, 206 | ); 207 | buildRules = ( 208 | ); 209 | dependencies = ( 210 | 6CB983C81C97E54A0057AB1C /* PBXTargetDependency */, 211 | ); 212 | name = VKMsgSend_ProjUITests; 213 | productName = VKMsgSend_ProjUITests; 214 | productReference = 6CB983C61C97E54A0057AB1C /* VKMsgSend_ProjUITests.xctest */; 215 | productType = "com.apple.product-type.bundle.ui-testing"; 216 | }; 217 | /* End PBXNativeTarget section */ 218 | 219 | /* Begin PBXProject section */ 220 | 6CB9839A1C97E54A0057AB1C /* Project object */ = { 221 | isa = PBXProject; 222 | attributes = { 223 | LastUpgradeCheck = 0720; 224 | ORGANIZATIONNAME = Awhisper; 225 | TargetAttributes = { 226 | 6CB983A11C97E54A0057AB1C = { 227 | CreatedOnToolsVersion = 7.2.1; 228 | }; 229 | 6CB983BA1C97E54A0057AB1C = { 230 | CreatedOnToolsVersion = 7.2.1; 231 | TestTargetID = 6CB983A11C97E54A0057AB1C; 232 | }; 233 | 6CB983C51C97E54A0057AB1C = { 234 | CreatedOnToolsVersion = 7.2.1; 235 | TestTargetID = 6CB983A11C97E54A0057AB1C; 236 | }; 237 | }; 238 | }; 239 | buildConfigurationList = 6CB9839D1C97E54A0057AB1C /* Build configuration list for PBXProject "VKMsgSend_Proj" */; 240 | compatibilityVersion = "Xcode 3.2"; 241 | developmentRegion = English; 242 | hasScannedForEncodings = 0; 243 | knownRegions = ( 244 | en, 245 | Base, 246 | ); 247 | mainGroup = 6CB983991C97E54A0057AB1C; 248 | productRefGroup = 6CB983A31C97E54A0057AB1C /* Products */; 249 | projectDirPath = ""; 250 | projectRoot = ""; 251 | targets = ( 252 | 6CB983A11C97E54A0057AB1C /* VKMsgSend_Proj */, 253 | 6CB983BA1C97E54A0057AB1C /* VKMsgSend_ProjTests */, 254 | 6CB983C51C97E54A0057AB1C /* VKMsgSend_ProjUITests */, 255 | ); 256 | }; 257 | /* End PBXProject section */ 258 | 259 | /* Begin PBXResourcesBuildPhase section */ 260 | 6CB983A01C97E54A0057AB1C /* Resources */ = { 261 | isa = PBXResourcesBuildPhase; 262 | buildActionMask = 2147483647; 263 | files = ( 264 | 6CB983B51C97E54A0057AB1C /* LaunchScreen.storyboard in Resources */, 265 | 6CB983B21C97E54A0057AB1C /* Assets.xcassets in Resources */, 266 | 6CB983B01C97E54A0057AB1C /* Main.storyboard in Resources */, 267 | ); 268 | runOnlyForDeploymentPostprocessing = 0; 269 | }; 270 | 6CB983B91C97E54A0057AB1C /* Resources */ = { 271 | isa = PBXResourcesBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | ); 275 | runOnlyForDeploymentPostprocessing = 0; 276 | }; 277 | 6CB983C41C97E54A0057AB1C /* Resources */ = { 278 | isa = PBXResourcesBuildPhase; 279 | buildActionMask = 2147483647; 280 | files = ( 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | /* End PBXResourcesBuildPhase section */ 285 | 286 | /* Begin PBXSourcesBuildPhase section */ 287 | 6CB9839E1C97E54A0057AB1C /* Sources */ = { 288 | isa = PBXSourcesBuildPhase; 289 | buildActionMask = 2147483647; 290 | files = ( 291 | 6CB983E01C97E62A0057AB1C /* VKMsgSend.m in Sources */, 292 | 6CB983AD1C97E54A0057AB1C /* ViewController.m in Sources */, 293 | 6CB983AA1C97E54A0057AB1C /* AppDelegate.m in Sources */, 294 | 6CB983E31C97E6CA0057AB1C /* testClassA.m in Sources */, 295 | 6CB983A71C97E54A0057AB1C /* main.m in Sources */, 296 | ); 297 | runOnlyForDeploymentPostprocessing = 0; 298 | }; 299 | 6CB983B71C97E54A0057AB1C /* Sources */ = { 300 | isa = PBXSourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | 6CB983C01C97E54A0057AB1C /* VKMsgSend_ProjTests.m in Sources */, 304 | ); 305 | runOnlyForDeploymentPostprocessing = 0; 306 | }; 307 | 6CB983C21C97E54A0057AB1C /* Sources */ = { 308 | isa = PBXSourcesBuildPhase; 309 | buildActionMask = 2147483647; 310 | files = ( 311 | 6CB983CB1C97E54A0057AB1C /* VKMsgSend_ProjUITests.m in Sources */, 312 | ); 313 | runOnlyForDeploymentPostprocessing = 0; 314 | }; 315 | /* End PBXSourcesBuildPhase section */ 316 | 317 | /* Begin PBXTargetDependency section */ 318 | 6CB983BD1C97E54A0057AB1C /* PBXTargetDependency */ = { 319 | isa = PBXTargetDependency; 320 | target = 6CB983A11C97E54A0057AB1C /* VKMsgSend_Proj */; 321 | targetProxy = 6CB983BC1C97E54A0057AB1C /* PBXContainerItemProxy */; 322 | }; 323 | 6CB983C81C97E54A0057AB1C /* PBXTargetDependency */ = { 324 | isa = PBXTargetDependency; 325 | target = 6CB983A11C97E54A0057AB1C /* VKMsgSend_Proj */; 326 | targetProxy = 6CB983C71C97E54A0057AB1C /* PBXContainerItemProxy */; 327 | }; 328 | /* End PBXTargetDependency section */ 329 | 330 | /* Begin PBXVariantGroup section */ 331 | 6CB983AE1C97E54A0057AB1C /* Main.storyboard */ = { 332 | isa = PBXVariantGroup; 333 | children = ( 334 | 6CB983AF1C97E54A0057AB1C /* Base */, 335 | ); 336 | name = Main.storyboard; 337 | sourceTree = ""; 338 | }; 339 | 6CB983B31C97E54A0057AB1C /* LaunchScreen.storyboard */ = { 340 | isa = PBXVariantGroup; 341 | children = ( 342 | 6CB983B41C97E54A0057AB1C /* Base */, 343 | ); 344 | name = LaunchScreen.storyboard; 345 | sourceTree = ""; 346 | }; 347 | /* End PBXVariantGroup section */ 348 | 349 | /* Begin XCBuildConfiguration section */ 350 | 6CB983CD1C97E54A0057AB1C /* Debug */ = { 351 | isa = XCBuildConfiguration; 352 | buildSettings = { 353 | ALWAYS_SEARCH_USER_PATHS = NO; 354 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 355 | CLANG_CXX_LIBRARY = "libc++"; 356 | CLANG_ENABLE_MODULES = YES; 357 | CLANG_ENABLE_OBJC_ARC = YES; 358 | CLANG_WARN_BOOL_CONVERSION = YES; 359 | CLANG_WARN_CONSTANT_CONVERSION = YES; 360 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 361 | CLANG_WARN_EMPTY_BODY = YES; 362 | CLANG_WARN_ENUM_CONVERSION = YES; 363 | CLANG_WARN_INT_CONVERSION = YES; 364 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 365 | CLANG_WARN_UNREACHABLE_CODE = YES; 366 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 367 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 368 | COPY_PHASE_STRIP = NO; 369 | DEBUG_INFORMATION_FORMAT = dwarf; 370 | ENABLE_STRICT_OBJC_MSGSEND = YES; 371 | ENABLE_TESTABILITY = YES; 372 | GCC_C_LANGUAGE_STANDARD = gnu99; 373 | GCC_DYNAMIC_NO_PIC = NO; 374 | GCC_NO_COMMON_BLOCKS = YES; 375 | GCC_OPTIMIZATION_LEVEL = 0; 376 | GCC_PREPROCESSOR_DEFINITIONS = ( 377 | "DEBUG=1", 378 | "$(inherited)", 379 | ); 380 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 381 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 382 | GCC_WARN_UNDECLARED_SELECTOR = YES; 383 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 384 | GCC_WARN_UNUSED_FUNCTION = YES; 385 | GCC_WARN_UNUSED_VARIABLE = YES; 386 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 387 | MTL_ENABLE_DEBUG_INFO = YES; 388 | ONLY_ACTIVE_ARCH = YES; 389 | SDKROOT = iphoneos; 390 | TARGETED_DEVICE_FAMILY = "1,2"; 391 | }; 392 | name = Debug; 393 | }; 394 | 6CB983CE1C97E54A0057AB1C /* Release */ = { 395 | isa = XCBuildConfiguration; 396 | buildSettings = { 397 | ALWAYS_SEARCH_USER_PATHS = NO; 398 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 399 | CLANG_CXX_LIBRARY = "libc++"; 400 | CLANG_ENABLE_MODULES = YES; 401 | CLANG_ENABLE_OBJC_ARC = YES; 402 | CLANG_WARN_BOOL_CONVERSION = YES; 403 | CLANG_WARN_CONSTANT_CONVERSION = YES; 404 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 405 | CLANG_WARN_EMPTY_BODY = YES; 406 | CLANG_WARN_ENUM_CONVERSION = YES; 407 | CLANG_WARN_INT_CONVERSION = YES; 408 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 409 | CLANG_WARN_UNREACHABLE_CODE = YES; 410 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 411 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 412 | COPY_PHASE_STRIP = NO; 413 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 414 | ENABLE_NS_ASSERTIONS = NO; 415 | ENABLE_STRICT_OBJC_MSGSEND = YES; 416 | GCC_C_LANGUAGE_STANDARD = gnu99; 417 | GCC_NO_COMMON_BLOCKS = YES; 418 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 419 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 420 | GCC_WARN_UNDECLARED_SELECTOR = YES; 421 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 422 | GCC_WARN_UNUSED_FUNCTION = YES; 423 | GCC_WARN_UNUSED_VARIABLE = YES; 424 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 425 | MTL_ENABLE_DEBUG_INFO = NO; 426 | SDKROOT = iphoneos; 427 | TARGETED_DEVICE_FAMILY = "1,2"; 428 | VALIDATE_PRODUCT = YES; 429 | }; 430 | name = Release; 431 | }; 432 | 6CB983D01C97E54A0057AB1C /* Debug */ = { 433 | isa = XCBuildConfiguration; 434 | buildSettings = { 435 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 436 | INFOPLIST_FILE = VKMsgSend_Proj/Info.plist; 437 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 438 | PRODUCT_BUNDLE_IDENTIFIER = "com.awhisper.test.VKMsgSend-Proj"; 439 | PRODUCT_NAME = "$(TARGET_NAME)"; 440 | }; 441 | name = Debug; 442 | }; 443 | 6CB983D11C97E54A0057AB1C /* Release */ = { 444 | isa = XCBuildConfiguration; 445 | buildSettings = { 446 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 447 | INFOPLIST_FILE = VKMsgSend_Proj/Info.plist; 448 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 449 | PRODUCT_BUNDLE_IDENTIFIER = "com.awhisper.test.VKMsgSend-Proj"; 450 | PRODUCT_NAME = "$(TARGET_NAME)"; 451 | }; 452 | name = Release; 453 | }; 454 | 6CB983D31C97E54A0057AB1C /* Debug */ = { 455 | isa = XCBuildConfiguration; 456 | buildSettings = { 457 | BUNDLE_LOADER = "$(TEST_HOST)"; 458 | INFOPLIST_FILE = VKMsgSend_ProjTests/Info.plist; 459 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 460 | PRODUCT_BUNDLE_IDENTIFIER = "com.awhisper.test.VKMsgSend-ProjTests"; 461 | PRODUCT_NAME = "$(TARGET_NAME)"; 462 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VKMsgSend_Proj.app/VKMsgSend_Proj"; 463 | }; 464 | name = Debug; 465 | }; 466 | 6CB983D41C97E54A0057AB1C /* Release */ = { 467 | isa = XCBuildConfiguration; 468 | buildSettings = { 469 | BUNDLE_LOADER = "$(TEST_HOST)"; 470 | INFOPLIST_FILE = VKMsgSend_ProjTests/Info.plist; 471 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 472 | PRODUCT_BUNDLE_IDENTIFIER = "com.awhisper.test.VKMsgSend-ProjTests"; 473 | PRODUCT_NAME = "$(TARGET_NAME)"; 474 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VKMsgSend_Proj.app/VKMsgSend_Proj"; 475 | }; 476 | name = Release; 477 | }; 478 | 6CB983D61C97E54A0057AB1C /* Debug */ = { 479 | isa = XCBuildConfiguration; 480 | buildSettings = { 481 | INFOPLIST_FILE = VKMsgSend_ProjUITests/Info.plist; 482 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 483 | PRODUCT_BUNDLE_IDENTIFIER = "com.awhisper.test.VKMsgSend-ProjUITests"; 484 | PRODUCT_NAME = "$(TARGET_NAME)"; 485 | TEST_TARGET_NAME = VKMsgSend_Proj; 486 | USES_XCTRUNNER = YES; 487 | }; 488 | name = Debug; 489 | }; 490 | 6CB983D71C97E54A0057AB1C /* Release */ = { 491 | isa = XCBuildConfiguration; 492 | buildSettings = { 493 | INFOPLIST_FILE = VKMsgSend_ProjUITests/Info.plist; 494 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 495 | PRODUCT_BUNDLE_IDENTIFIER = "com.awhisper.test.VKMsgSend-ProjUITests"; 496 | PRODUCT_NAME = "$(TARGET_NAME)"; 497 | TEST_TARGET_NAME = VKMsgSend_Proj; 498 | USES_XCTRUNNER = YES; 499 | }; 500 | name = Release; 501 | }; 502 | /* End XCBuildConfiguration section */ 503 | 504 | /* Begin XCConfigurationList section */ 505 | 6CB9839D1C97E54A0057AB1C /* Build configuration list for PBXProject "VKMsgSend_Proj" */ = { 506 | isa = XCConfigurationList; 507 | buildConfigurations = ( 508 | 6CB983CD1C97E54A0057AB1C /* Debug */, 509 | 6CB983CE1C97E54A0057AB1C /* Release */, 510 | ); 511 | defaultConfigurationIsVisible = 0; 512 | defaultConfigurationName = Release; 513 | }; 514 | 6CB983CF1C97E54A0057AB1C /* Build configuration list for PBXNativeTarget "VKMsgSend_Proj" */ = { 515 | isa = XCConfigurationList; 516 | buildConfigurations = ( 517 | 6CB983D01C97E54A0057AB1C /* Debug */, 518 | 6CB983D11C97E54A0057AB1C /* Release */, 519 | ); 520 | defaultConfigurationIsVisible = 0; 521 | defaultConfigurationName = Release; 522 | }; 523 | 6CB983D21C97E54A0057AB1C /* Build configuration list for PBXNativeTarget "VKMsgSend_ProjTests" */ = { 524 | isa = XCConfigurationList; 525 | buildConfigurations = ( 526 | 6CB983D31C97E54A0057AB1C /* Debug */, 527 | 6CB983D41C97E54A0057AB1C /* Release */, 528 | ); 529 | defaultConfigurationIsVisible = 0; 530 | defaultConfigurationName = Release; 531 | }; 532 | 6CB983D51C97E54A0057AB1C /* Build configuration list for PBXNativeTarget "VKMsgSend_ProjUITests" */ = { 533 | isa = XCConfigurationList; 534 | buildConfigurations = ( 535 | 6CB983D61C97E54A0057AB1C /* Debug */, 536 | 6CB983D71C97E54A0057AB1C /* Release */, 537 | ); 538 | defaultConfigurationIsVisible = 0; 539 | defaultConfigurationName = Release; 540 | }; 541 | /* End XCConfigurationList section */ 542 | }; 543 | rootObject = 6CB9839A1C97E54A0057AB1C /* Project object */; 544 | } 545 | -------------------------------------------------------------------------------- /VKMsgSend_Proj.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /VKMsgSend_Proj.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /VKMsgSend_Proj.xcodeproj/project.xcworkspace/xcuserdata/Awhisper.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Awhisper/VKMsgSend/b4921c26fed01c4d0887bd3d2941d40499cf8937/VKMsgSend_Proj.xcodeproj/project.xcworkspace/xcuserdata/Awhisper.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /VKMsgSend_Proj.xcodeproj/xcuserdata/Awhisper.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 40 | 52 | 53 | 54 | 56 | 68 | 69 | 70 | 72 | 84 | 85 | 86 | 88 | 100 | 101 | 102 | 104 | 116 | 117 | 118 | 120 | 132 | 133 | 134 | 136 | 148 | 149 | 150 | 152 | 164 | 165 | 166 | 168 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /VKMsgSend_Proj.xcodeproj/xcuserdata/Awhisper.xcuserdatad/xcschemes/VKMsgSend_Proj.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /VKMsgSend_Proj.xcodeproj/xcuserdata/Awhisper.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | VKMsgSend_Proj.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 6CB983A11C97E54A0057AB1C 16 | 17 | primary 18 | 19 | 20 | 6CB983BA1C97E54A0057AB1C 21 | 22 | primary 23 | 24 | 25 | 6CB983C51C97E54A0057AB1C 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /VKMsgSend_Proj/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // VKMsgSend_Proj 4 | // 5 | // Created by Awhisper on 16/3/15. 6 | // Copyright © 2016年 Awhisper. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /VKMsgSend_Proj/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // VKMsgSend_Proj 4 | // 5 | // Created by Awhisper on 16/3/15. 6 | // Copyright © 2016年 Awhisper. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /VKMsgSend_Proj/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /VKMsgSend_Proj/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /VKMsgSend_Proj/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /VKMsgSend_Proj/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /VKMsgSend_Proj/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // vk_msgSend_proj 4 | // 5 | // Created by Awhisper on 15/12/26. 6 | // Copyright © 2015年 Awhisper. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /VKMsgSend_Proj/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // vk_msgSend_proj 4 | // 5 | // Created by Awhisper on 15/12/26. 6 | // Copyright © 2015年 Awhisper. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "VKMsgSend.h" 11 | #import 12 | @interface ViewController () 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | 19 | #pragma clang diagnostic push 20 | #pragma clang diagnostic ignored "-Wundeclared-selector" 21 | 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | // Do any additional setup after loading the view, typically from a nib. 26 | 27 | Class cls = NSClassFromString(@"testClassA"); 28 | 29 | id abc = [[cls alloc]init]; 30 | 31 | NSError *err; 32 | 33 | //this warning is ok Selector is in testClassA 34 | NSString *return1 = [abc VKCallSelector:@selector(testfunction:withB:) error:&err,4,3.5f]; 35 | NSLog(@"%@",return1); 36 | 37 | NSNumber *return3 = [abc VKCallSelectorName:@"testfunction:withB:withC:" error:nil,4,3.5,@"haha"]; 38 | NSInteger tureReturn3 = [return3 integerValue]; 39 | NSLog(@"%@",@(tureReturn3)); 40 | 41 | NSString *return4 = [abc VKCallSelectorName:@"testfunction:withB:withC:withD:" error:nil,4,3.5,nil, CGRectMake(10, 10, 10, 10)]; 42 | NSLog(@"%@",return4); 43 | 44 | NSError* testerr2; 45 | [abc VKCallSelectorName:@"testFunctionError:" error:nil,&testerr2]; 46 | 47 | NSLog(@"see more test case in XCTest Target"); 48 | NSLog(@"vk_msgSend_projTests"); 49 | 50 | [abc VKCallSelector:@selector(testFunctionError:) error:nil,nil]; 51 | 52 | //这是一段展示 performselector 缺点和不足的代码,有注释中文解释 53 | [self performShow]; 54 | //这是一段展示 objc_msgsend 缺点和不足的代码,有注释和中文解释 55 | [self msgsendShow]; 56 | //这是对比展示 VKMsgSend的代码 57 | [self vkshow]; 58 | 59 | [self issueTest]; 60 | } 61 | 62 | -(void)performShow 63 | { 64 | 65 | Class cls = NSClassFromString(@"testClassA"); 66 | 67 | id abc = [[cls alloc]init]; 68 | 69 | //-(NSString*)testfunction:(int)num withB:(float)boolv 70 | NSString * result = [abc performSelector:@selector(testfunction:withB:) withObject:@4 withObject:@3.5]; 71 | NSLog(@"%@",result); 72 | //并且只支持id,如果你敢把基础数值类型封装成number传进去,数值还是错乱的 73 | //这样代码跑进去 int 传了个NSNumber进去 函数内指针全乱,参数值都飞了 74 | 75 | //3个参数就不支持了,打开注释你会发现,就没有传3个参数的方法 76 | // [abc performSelector:@selector(testfunction:withB:withC:) withObject:@4.5 withObject:@3 withObject:@"ssss"]; 77 | } 78 | 79 | -(void)msgsendShow 80 | { 81 | Class cls = NSClassFromString(@"testClassA"); 82 | 83 | id abc = [[cls alloc]init]; 84 | // NSString *result = objc_msgSend(abc, @selector(testfunction:withB:), 4, 3.5); 85 | 86 | //很抱歉上面这样的方法,看着用的很方便,但是在iOS 64位下会直接崩溃,xcode8下是直接无法编译 87 | NSString *result2 = ((NSString* (*)(id, SEL, int,float))objc_msgSend)(abc, @selector(testfunction:withB:), 4, 3.5); 88 | 89 | //看到没必须这么费劲的写一坨C语言的函数指针强转才可以 90 | 91 | NSLog(@"%@",result2); 92 | } 93 | 94 | -(void)vkshow 95 | { 96 | //理想状态下 旧的 objc_msgSend就已经很方便了,但是已经不能这么用了,那我就封装出了一个runtime工具 97 | Class cls = NSClassFromString(@"testClassA"); 98 | id abc = [[cls alloc]init]; 99 | NSError * error; 100 | 101 | //很方便吧 102 | [abc VKCallSelectorName:@"testfunction:withB:" error:&error,4,3.5]; 103 | //支持所有基础类型,结构体,id类型,class类型,selector类型,block类型,还有指针类型 ** 104 | 105 | //如果是使用类方法,还可以直接通过类名NSString 106 | [@"testClassA" VKCallClassSelectorName:@"testfunction:withB:withH" error:&error,4,3.5,@"aaa"]; 107 | 108 | //如果是实例方法,可以直接通过类名NSString,调用init selector,哪怕initWithXX:XX:等自定义的初始化函数都可以 109 | id abcc = [@"testClassA" VKCallClassAllocInitSelectorName:@"init" error:nil]; 110 | NSLog(@"%@",abcc); 111 | //省去了手写NSClassFromString 的事情 112 | 113 | } 114 | 115 | -(void)issueTest{ 116 | //写个匿名block 然后传进去 117 | void(^tempblock)(void) = ^(void){ 118 | NSLog(@"==== block run ===="); 119 | }; 120 | NSDictionary *params =@{@"callback":[tempblock copy]}; 121 | NSError *error; 122 | id result = [@"testClassA" VKCallClassAllocInitSelectorName:@"initWithParams:" error:&error, params, nil]; 123 | } 124 | 125 | 126 | #pragma clang diagnostic pop 127 | 128 | - (void)didReceiveMemoryWarning { 129 | [super didReceiveMemoryWarning]; 130 | // Dispose of any resources that can be recreated. 131 | } 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /VKMsgSend_Proj/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // VKMsgSend_Proj 4 | // 5 | // Created by Awhisper on 16/3/15. 6 | // Copyright © 2016年 Awhisper. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /VKMsgSend_Proj/testClassA.h: -------------------------------------------------------------------------------- 1 | // 2 | // testClassA.h 3 | // IdSelectorCall 4 | // 5 | // Created by Awhisper on 15/12/25. 6 | // Copyright © 2015年 Awhisper. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface testClassA : NSObject 12 | 13 | -(instancetype)initWithParams:(NSDictionary *)dic; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /VKMsgSend_Proj/testClassA.m: -------------------------------------------------------------------------------- 1 | // 2 | // testClassA.m 3 | // IdSelectorCall 4 | // 5 | // Created by Awhisper on 15/12/25. 6 | // Copyright © 2015年 Awhisper. All rights reserved. 7 | // 8 | 9 | #import "testClassA.h" 10 | #import 11 | 12 | typedef void(^blockType)(void); 13 | @interface testClassA () 14 | 15 | @property(nonatomic,copy) blockType block; 16 | 17 | @property(nonatomic,copy) NSMutableDictionary *dic; 18 | 19 | @end 20 | 21 | @implementation testClassA 22 | 23 | -(instancetype)initWithParams:(NSDictionary *)dic{ 24 | self = [super init]; 25 | if (self) { 26 | void(^callback)(void) = [dic objectForKey:@"callback"]; 27 | if (callback) { 28 | callback(); 29 | } 30 | } 31 | return self; 32 | } 33 | 34 | +(NSInteger)testfunction:(int)num withB:(float)boolv withH:(NSString*)str{ 35 | return 1; 36 | } 37 | 38 | -(NSString*)testfunction:(int)num withB:(float)boolv{ 39 | NSLog(@"I'm testfunction: withB:"); 40 | return @"hello"; 41 | } 42 | 43 | -(NSInteger)testfunction:(int)num withB:(float)boolv withC:(NSString*)str{ 44 | NSLog(@"I'm testfunction: withB: withC:"); 45 | return 1; 46 | } 47 | 48 | -(NSString*)testfunction:(int)num withB:(float)boolv withC:(NSString*)str withD:(CGRect)rect{ 49 | NSLog(@"I'm testfunction: withB: withC: withD:"); 50 | return @"hello"; 51 | } 52 | 53 | -(CGRect)testfunction:(int)num withB:(float)boolv withC:(NSString*)str withE:(NSRange)rect{ 54 | NSLog(@"I'm testfunction: withB: withC: withD: withE:"); 55 | return CGRectZero; 56 | } 57 | 58 | -(NSString *)testfunctionWithProtocol:(id)protocol 59 | { 60 | Protocol *pro = (Protocol*)protocol; 61 | NSLog(@"%@",NSStringFromProtocol(pro)); 62 | return @"hello"; 63 | } 64 | 65 | -(NSString *)testFunctionWithSEL:(SEL)selector 66 | { 67 | return NSStringFromSelector(selector); 68 | } 69 | 70 | -(void)testFunctionWithBlock:(blockType)block 71 | { 72 | self.block = block; 73 | } 74 | 75 | -(void)testFunctionCallBlock{ 76 | if (self.block) { 77 | self.block(); 78 | } 79 | } 80 | 81 | -(void)testFunctionIDStar:(NSMutableArray **)arr{ 82 | if (arr) { 83 | [*arr addObject:@"aa"]; 84 | } 85 | } 86 | 87 | -(void)testFunctionError:(NSError **)error{ 88 | if (error) { 89 | *error = [NSError errorWithDomain:@"xxxx" code:0 userInfo:nil]; 90 | } 91 | } 92 | 93 | -(BOOL)testFunctionObject:(id)obj isKindOfClass:(Class)cls 94 | { 95 | BOOL ret = [obj isKindOfClass:cls]; 96 | return ret; 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /VKMsgSend_ProjTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /VKMsgSend_ProjTests/VKMsgSend_ProjTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // VKMsgSend_projTests.m 3 | // VKMsgSend_projTests 4 | // 5 | // Created by Awhisper on 16/1/7. 6 | // Copyright © 2016年 Awhisper. All rights reserved. 7 | // 8 | 9 | #import 10 | //#import "NSObject+VKMsgSend.h" 11 | #import "testClassA.h" 12 | #import "VKMsgSend.h" 13 | @interface VKMsgSend_projTests : XCTestCase 14 | 15 | @end 16 | 17 | @implementation VKMsgSend_projTests 18 | 19 | 20 | #pragma clang diagnostic push 21 | #pragma clang diagnostic ignored "-Wundeclared-selector" 22 | 23 | 24 | - (void)setUp { 25 | [super setUp]; 26 | // Put setup code here. This method is called before the invocation of each test method in the class. 27 | } 28 | 29 | - (void)tearDown { 30 | // Put teardown code here. This method is called after the invocation of each test method in the class. 31 | [super tearDown]; 32 | } 33 | 34 | - (void)testExample { 35 | // This is an example of a functional test case. 36 | // Use XCTAssert and related functions to verify your tests produce the correct results. 37 | 38 | 39 | 40 | Class cls = NSClassFromString(@"testClassA"); 41 | 42 | NSNumber* clsreturn = [(id)cls VKCallSelector:@selector(testfunction:withB:withH:) error:nil,4,3.5,@"haha"]; 43 | XCTAssertEqual([clsreturn intValue], 1); 44 | 45 | NSNumber* clsreturn2 = [@"testClassA" VKCallClassSelector:@selector(testfunction:withB:withH:) error:nil,4,3.5,@"haha"]; 46 | XCTAssertEqual([clsreturn2 intValue], 1); 47 | 48 | NSNumber* clsreturn3 = [@"testClassA" VKCallClassSelectorName:@"testfunction:withB:withH:" error:nil,4,3.5,@"haha"]; 49 | XCTAssertEqual([clsreturn3 intValue], 1); 50 | 51 | 52 | 53 | NSNumber* clsallocreturn1 = [@"testClassA" VKCallClassAllocInitSelector:@selector(testfunction:withB:withC:) error:nil,4,3.5,@"haha"]; 54 | XCTAssertEqual([clsallocreturn1 intValue], 1); 55 | 56 | NSNumber* clsallocreturn2 = [@"testClassA" VKCallClassAllocInitSelectorName:@"testfunction:withB:withC:" error:nil,4,3.5,@"haha"]; 57 | XCTAssertEqual([clsallocreturn2 intValue], 1); 58 | 59 | NSError *clsreturnError; 60 | NSNumber* clsreturn4 = [@"testClassAA" VKCallClassSelectorName:@"testfunction:withB:withH:" error:&clsreturnError,4,3.5,@"haha"]; 61 | XCTAssert(!clsreturn4); 62 | XCTAssert(clsreturnError); 63 | 64 | id abc = [[cls alloc]init]; 65 | 66 | NSError *err; 67 | 68 | NSString *return1 = [abc VKCallSelector:@selector(testfunction:withB:) error:&err,4,3.5f]; 69 | XCTAssert([return1 isEqualToString:@"hello"]); 70 | 71 | NSNumber *return2 = [[abc class] VKCallSelector:@selector(testfunction:withB:withH:) error:nil,4,3.5,@"haha"]; 72 | NSInteger tureReturn2 = [return2 integerValue]; 73 | XCTAssertEqual(tureReturn2, 1); 74 | 75 | NSNumber *return3 = [abc VKCallSelectorName:@"testfunction:withB:withC:" error:nil,4,3.5,@"haha"]; 76 | NSInteger tureReturn3 = [return3 integerValue]; 77 | XCTAssertEqual(tureReturn3, 1); 78 | 79 | NSString *return4 = [abc VKCallSelectorName:@"testfunction:withB:withC:withD:" error:nil,4,3.5,nil, CGRectMake(10, 10, 10, 10)]; 80 | XCTAssert([return4 isEqualToString:@"hello"]); 81 | 82 | NSValue *return5 = [abc VKCallSelector:@selector(testfunction:withB:withC:withE:) error:nil,4,3.5,@"haha", NSMakeRange(1, 3)]; 83 | CGRect trueReturn5 = [return5 CGRectValue]; 84 | XCTAssert(CGRectEqualToRect(trueReturn5, CGRectZero)); 85 | 86 | 87 | SEL argsel = @selector(testwoooo); 88 | NSString* return6 = [abc VKCallSelector:@selector(testFunctionWithSEL:) error:nil,argsel]; 89 | XCTAssert([return6 isEqualToString:NSStringFromSelector(argsel)]); 90 | //写个匿名block 然后传进去 91 | void(^tempblock)(void) = ^(void){ 92 | NSLog(@"==== block run ===="); 93 | }; 94 | [abc VKCallSelector:@selector(testFunctionWithBlock:) error:nil,tempblock]; 95 | 96 | [abc VKCallSelector:@selector(testFunctionCallBlock) error:nil]; 97 | 98 | 99 | 100 | NSMutableArray* testerr = [[NSMutableArray alloc]init]; 101 | [abc VKCallSelector:@selector(testFunctionIDStar:) error:nil,&testerr]; 102 | XCTAssert(testerr.count>0); 103 | 104 | 105 | NSString *teststr = @"hello"; 106 | Class stringcls = [teststr class]; 107 | NSNumber *isCls = [abc VKCallSelectorName:@"testFunctionObject:isKindOfClass:" error:nil,teststr,stringcls]; 108 | BOOL isClsBool = [isCls boolValue]; 109 | XCTAssertEqual(isClsBool, 1); 110 | 111 | NSError* testerr2; 112 | [abc VKCallSelector:@selector(testFunctionError:) error:nil,&testerr2]; 113 | XCTAssert(testerr2); 114 | 115 | [abc VKCallSelector:@selector(testFunctionError:) error:nil,nil]; 116 | XCTAssert(YES); 117 | } 118 | 119 | - (void)testPerformanceExample { 120 | // This is an example of a performance test case. 121 | [self measureBlock:^{ 122 | // Put the code you want to measure the time of here. 123 | }]; 124 | } 125 | 126 | 127 | #pragma clang diagnostic pop 128 | @end 129 | -------------------------------------------------------------------------------- /VKMsgSend_ProjUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /VKMsgSend_ProjUITests/VKMsgSend_ProjUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // VKMsgSend_ProjUITests.m 3 | // VKMsgSend_ProjUITests 4 | // 5 | // Created by Awhisper on 16/3/15. 6 | // Copyright © 2016年 Awhisper. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface VKMsgSend_ProjUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation VKMsgSend_ProjUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | --------------------------------------------------------------------------------