├── NSInvocation+Block.h ├── LICENSE ├── README.md └── NSInvocation+Block.m /NSInvocation+Block.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSInvocation+Block.h 3 | // NSInvocation+Block 4 | // 5 | // Created by deput on 12/11/15. 6 | // Copyright © 2015 deput. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSInvocation (Block) 12 | + (instancetype) invocationWithBlock:(id) block; 13 | + (instancetype) invocationWithBlockAndArguments:(id) block ,...; 14 | @end 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Guo Yu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NSInvocation-Block 2 | 3 | ## Objective 4 | NSInvocation-Block is a NSInvocation category to create NSInvocation with block 5 | 6 | ## Usage 7 | Given 8 | ```objc 9 | void (^myBlock)(id, NSString*, NSArray*) = ^(id obj1, NSString* name, NSArray* array) { 10 | NSLog(@"%@",@"Hey!"); 11 | }; 12 | ``` 13 | We can create an invocation: 14 | ```objc 15 | NSInvocation* inv = [NSInvocation invocationWithBlock:myBlock]; 16 | ``` 17 | Or with arguments: 18 | 19 | ```objc 20 | NSInvocation* inv = [NSInvocation invocationWithBlockAndArguments:myBlock,[NSObject new],@"Hello",@[@1,@2,@3]]; 21 | ``` 22 | 23 | ## Known issues 24 | 1. Arguments of struct, union or C-style array type are not supported yet. 25 | 26 | ## Update 27 | I attempted to add support for struct and union. 28 | ```objc 29 | NSUInteger valueSizeInByte = 0; 30 | NSUInteger align = 0; 31 | NSGetSizeAndAlignment(argType, &valueSizeInByte, &align); 32 | void* buffer = malloc(valueSizeInByte); 33 | if (align == 4) { 34 | for (int ii = 0; ii < valueSizeInByte / align ; ii++) { 35 | UInt32 val = va_arg(args,UInt32); 36 | memcpy(((UInt32*)buffer+ii), &val, align); 37 | } 38 | }else if(align == 8){ 39 | for (int ii = 0; ii < valueSizeInByte / align ; ii++) { 40 | UInt64 val = va_arg(args,UInt64); 41 | memcpy(((UInt64*)buffer+ii), &val, align); 42 | } 43 | } 44 | [invocation setArgument:buffer atIndex:1 + i]; 45 | free(buffer); 46 | ``` 47 | Anyhow, code only worked for struct on device! 48 | Besides, the use of `buffer` in the code snippet is not safe. Actually we can't see implementation of NSInvoation, do not know how it behaves when calling `-[NSInvoation retainArguments]`. 49 | 50 | In a word, I won't add this snippet before i figure it out. 51 | 52 | 53 | -------------------------------------------------------------------------------- /NSInvocation+Block.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSInvocation+Block.m 3 | // NSInvocation+Block 4 | // 5 | // Created by deput on 12/11/15. 6 | // Copyright © 2015 deput. All rights reserved. 7 | // 8 | 9 | #import "NSInvocation+Block.h" 10 | #import 11 | 12 | struct Block_literal_1 { 13 | void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock 14 | int flags; 15 | int reserved; 16 | void (*invoke)(void *, ...); 17 | struct Block_descriptor_1 { 18 | unsigned long int reserved; // NULL 19 | unsigned long int size; // sizeof(struct Block_literal_1) 20 | // optional helper functions 21 | // void (*copy_helper)(void *dst, void *src); // IFF (1<<25) 22 | // void (*dispose_helper)(void *src); // IFF (1<<25) 23 | // required ABI.2010.3.16 24 | // const char *signature; // IFF (1<<30) 25 | void* rest[1]; 26 | } *descriptor; 27 | // imported variables 28 | }; 29 | 30 | enum { 31 | BLOCK_HAS_COPY_DISPOSE = (1 << 25), 32 | BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code 33 | BLOCK_IS_GLOBAL = (1 << 28), 34 | BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE 35 | BLOCK_HAS_SIGNATURE = (1 << 30), 36 | }; 37 | 38 | static const char *__BlockSignature__(id blockObj) 39 | { 40 | struct Block_literal_1 *block = (__bridge void *)blockObj; 41 | struct Block_descriptor_1 *descriptor = block->descriptor; 42 | assert(block->flags & BLOCK_HAS_SIGNATURE); 43 | int offset = 0; 44 | if(block->flags & BLOCK_HAS_COPY_DISPOSE) 45 | offset += 2; 46 | return (char*)(descriptor->rest[offset]); 47 | } 48 | 49 | @implementation NSInvocation (Block) 50 | 51 | + (instancetype) invocationWithBlock:(id) block 52 | { 53 | NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:__BlockSignature__(block)]]; 54 | invocation.target = block; 55 | return invocation; 56 | } 57 | #define ARG_GET_SET(type) do { type val = 0; val = va_arg(args,type); [invocation setArgument:&val atIndex:1 + i];} while (0) 58 | + (instancetype) invocationWithBlockAndArguments:(id) block ,... 59 | { 60 | NSInvocation* invocation = [NSInvocation invocationWithBlock:block]; 61 | NSUInteger argsCount = invocation.methodSignature.numberOfArguments - 1; 62 | va_list args; 63 | va_start(args, block); 64 | for(NSUInteger i = 0; i < argsCount ; ++i){ 65 | const char* argType = [invocation.methodSignature getArgumentTypeAtIndex:i + 1]; 66 | if (argType[0] == _C_CONST) argType++; 67 | 68 | if (argType[0] == '@') { //id and block 69 | ARG_GET_SET(id); 70 | }else if (strcmp(argType, @encode(Class)) == 0 ){ //Class 71 | ARG_GET_SET(Class); 72 | }else if (strcmp(argType, @encode(IMP)) == 0 ){ //IMP 73 | ARG_GET_SET(IMP); 74 | }else if (strcmp(argType, @encode(SEL)) == 0) { //SEL 75 | ARG_GET_SET(SEL); 76 | }else if (strcmp(argType, @encode(double)) == 0){ // 77 | ARG_GET_SET(double); 78 | }else if (strcmp(argType, @encode(float)) == 0){ 79 | float val = 0; 80 | val = (float)va_arg(args,double); 81 | [invocation setArgument:&val atIndex:1 + i]; 82 | }else if (argType[0] == '^'){ //pointer ( andconst pointer) 83 | ARG_GET_SET(void*); 84 | }else if (strcmp(argType, @encode(char *)) == 0) { //char* (and const char*) 85 | ARG_GET_SET(char *); 86 | }else if (strcmp(argType, @encode(unsigned long)) == 0) { 87 | ARG_GET_SET(unsigned long); 88 | }else if (strcmp(argType, @encode(unsigned long long)) == 0) { 89 | ARG_GET_SET(unsigned long long); 90 | }else if (strcmp(argType, @encode(long)) == 0) { 91 | ARG_GET_SET(long); 92 | }else if (strcmp(argType, @encode(long long)) == 0) { 93 | ARG_GET_SET(long long); 94 | }else if (strcmp(argType, @encode(int)) == 0) { 95 | ARG_GET_SET(int); 96 | }else if (strcmp(argType, @encode(unsigned int)) == 0) { 97 | ARG_GET_SET(unsigned int); 98 | }else if (strcmp(argType, @encode(BOOL)) == 0 || strcmp(argType, @encode(bool)) == 0 99 | || strcmp(argType, @encode(char)) == 0 || strcmp(argType, @encode(unsigned char)) == 0 100 | || strcmp(argType, @encode(short)) == 0 || strcmp(argType, @encode(unsigned short)) == 0) { 101 | ARG_GET_SET(int); 102 | }else{ //struct union and array 103 | assert(false && "struct union array unsupported!") 104 | } 105 | } 106 | va_end(args); 107 | return invocation; 108 | } 109 | @end 110 | --------------------------------------------------------------------------------