BlocksKitãä»ã®ã©ã€ãã©ãªãªã©ã®æ¢è£œã®ãœãªã¥ãŒã·ã§ã³ããããŸããããããã®ãœãªã¥ãŒã·ã§ã³ã¯ãããã¯ãä¿åããã¿ãŒã²ãããèšå®ããæå®ãããã»ã¬ã¯ã¿ãŒãããããã¯ãåŒã³åºãããšã§ãã
ãªããã®èšäºãå¿ èŠãªã®ã§ããïŒ
ãããã¯ãåŒã³åºãã»ã¬ã¯ã¿ãŒãçæããæ¹æ³ãäœæãããã£ãã®ã§ãã ããã§è€éãªããšã¯äœã§ããïŒ imp_implementationWithBlock + class_addMethodãšã±ãŒã¹ãéããããŸãã ãããããã®ã¢ãããŒãã§ã¯ã1ã€ã®é倧ãªèŠä»¶ããããŸããããã¯ããããã¯ã®æåã®åŒæ°-ã¡ãœããã®ææè ã§ãã
ãã®èŠä»¶ãåé¿ããŠãããè¡ãæ¹æ³ã¯ïŒ
[button addTarget:self action:[self ax_lambda:^(UIButton *sender, UIEvent *event){ NSLog(@"click on button %@, event = %@", sender, event); }] forControlEvents:UIControlEventTouchUpInside]; [button addTarget:self action:[self ax_lambda:^{ NSLog(@"click"); }] forControlEvents:UIControlEventTouchUpInside];
ãŸãã¯ãã®ããã«
__block NSInteger sum = 0; [self performSelector:[self ax_lambda:^(NSNumber *argA, NSNumber *argB) { sum = [argA integerValue] + [argB integerValue]; }] withObject:@(2) withObject:@(3)]; //sum â 5 SEL selSum = [self ax_lambda:^NSInteger(NSInteger argA, NSInteger argB){ return argA + argB; }]; NSInteger(*funcSum)(id, SEL, NSInteger, NSInteger) = (NSInteger(*)(id, SEL, NSInteger, NSInteger))objc_msgSend; NSInteger sum2 = funcSum(self, selSum, 2, 3); //sum2 â 5
å®è£ ã¯éåžžã«èå³æ·±ãããšãå€æãããããç§ã¯ããã«ã€ããŠæžãããšã«ããŸããã
å®éãäž»ãªã¿ã¹ã¯ã¯ããããã¯åŒã³åºãã§selfã®æåã®åŒæ°ãåãé€ãããšã§ãã ããã¯ããœãªã¥ãŒã·ã§ã³å šäœã®æ ¹æ¬çãªåé¡ã§ãïŒãããå¯äžã®åé¡ã§ã¯ãªãããšã¯æ®å¿µã§ãïŒã
以åãç§ã¯ãããã¯ã«ã€ããŠå°ãæžããŸãããããããã¯ã¯ãªããžã§ã¯ãã§ããããšã«æ³šæããŠãã ãããã€ãŸããåŒã³åºãã¯NSInvocationãä»ããŠè¡ãããŸãã
ãããã¯ãåŒã³åºãããç¬éãååŸããNSInvocationã§ïŒåŒæ°ãã·ããããããšã§ïŒselfåŒæ°ãåé€ãããšãç®çã®çµæãåŸãããŸãã
ããã«ãéäžã§ç解ããå¿ èŠããããŸãã
AXProxyBlock
åé¡ã¯ããããã¯åŒã³åºãã®ç¬éã«ã©ã®ããã«äŸµå ¥ããã®ã§ããïŒ ãããã¯åŒã³åºããååŸããæ¹æ³ã¯ïŒ
ç§ã¯éåžžã«é »ç¹ã«ãã®ãã¬ãŒãºãæžããŸããããããã¯ã¯ãªããžã§ã¯ãã§ãã æçµåœ¢åŒã®objcã®ãªããžã§ã¯ãã¯æ§é äœã§ãã idã¯æ§é äœãžã®ãã€ã³ã¿ã§ãããããéãèš±å¯ãããŸãïŒ__bridgeãhelloïŒ ã
åœã®ãããã¯ãäœæã§ããããšãããããŸããã ãŸãããŸãã¯ãããã¯ã®ãããã·ã
ç§ã®ã¯ã©ã¹ã®ã€ã³ã¿ãŒãã§ãŒã¹ã¯æ¬¡ã®ãšããã§ãã
typedef void(^AXProxyBlockInterpose)(NSInvocation *invocation); @interface AXProxyBlock : NSProxy + (instancetype)initWithBlock:(id)block; - (void)setBeforeInvoke:(AXProxyBlockInterpose)beforeInvoke; - (NSString *)blockSignatureStringCTypes; @end
ãæ³åã®ãšãããsetBeforeInvokeã¯ããããã¯åŒæ°ã®ãããžãã¯ãå€æãå®è¡ã§ãããããã¯ãåãå ¥ããŸãã
blockSignatureStringCTypesã¯ããããã·ããããããã¯ã®çœ²åãè¿ããŸãã ããããŒãã¡ã€ã«ã«å«ãŸããŠããã®ã¯ãªãã§ããïŒ ããã«ã€ããŠã¯åŸã§ã
ä»ããå§ãŸãããã¥ã¡ã³ãããŒãžãžã®ãªã³ã¯
ããã¥ã¡ã³ããéå§ããããã«ããããã¯æ§é ãšåæåãäœæããŸãã
typedef struct AXBlockStruct_1 { unsigned long int reserved; unsigned long int size; void (*copy_helper)(void *dst, void *src); void (*dispose_helper)(void *src); const char *signature; } AXBlockStruct_1; typedef struct AXBlockStruct { void *isa; int flags; int reserved; void (*invoke)(void *, ...); struct AXBlockStruct_1 *descriptor; } AXBlockStruct; typedef NS_ENUM(NSUInteger, AXBlockFlag) { AXBlockFlag_HasCopyDispose = (1 << 25), AXBlockFlag_HasCtor = (1 << 26), AXBlockFlag_IsGlobal = (1 << 28), AXBlockFlag_HasStret = (1 << 29), AXBlockFlag_HasSignature = (1 << 30) };
ããã§ã¯ãã¯ã©ã¹ãèŠãŠã¿ãŸãããã
察å¿ããæ§é ãäœæããå¿
èŠããããŸãã
@interface AXProxyBlock () { // isa NSProxy, int _flags; int _reserved; IMP _invoke; AXBlockStruct_1 *_descriptor; // , , AXProxyBlockInterpose _beforeInvoke; id _block; NSMethodSignature *_blockMethodSignature; IMP _impBlockInvoke; } @end
ããã§ãåŒã³åºãæã«ã¯ã©ã¹ãåä¿¡ãããã¯ãæš¡å£ããå¿ èŠããããŸãã
äžèŽãããã£ãŒã«ãå€
- (instancetype)initWithBlock:(id)block { if (self != nil) { AXBlockStruct *blockRef = (__bridge AXBlockStruct *)block; _flags = blockRef->flags; _reserved = blockRef->reserved; _descriptor = calloc(1, sizeof(AXBlockStruct_1)); _descriptor->size = class_getInstanceSize([self class]); BOOL flag_stret = _flags & AXBlockFlag_HasStret; _invoke = (flag_stret ? (IMP)_objc_msgForward_stret : (IMP)_objc_msgForward); ...
ãããã®ãã£ãŒã«ãã®ç®çã®èª¬æã¯ããã¹ãŠåãclangããã¥ã¡ã³ãããŒãžã§èªãããšãã§ããŸã ã ããã§ããã£ãŒã«ãã¯åŒã³åºãæã®ãããã¯ã«å¯Ÿå¿ããŸãã
ãããã2ã€ã®éåžžã«éèŠãªivarããããŸãããããã¯ãäžèšã®ã¹ãã€ã©ãŒã«ã¯å«ãŸããŠããŸããããããã¯æ¢ã«ãããã¯ã³ãŒã«ãåç §ããŠããã®ã§ãããã«è©³ãã説æãããããã§ãã
_impBlockInvoke = (IMP)blockRef->invoke; _blockMethodSignature = [self blockMethodSignature];
_impBlockInvokeã¯ããããã¯åŒã³åºãé¢æ°ã®å®è£ ã§ãã ããã¯éåžžã®é¢æ°ãã€ã³ã¿ãŒã§ãããæåã§åŒã³åºãããšãã§ããŸãã
_blockMethodSignatureã¯ããããã¯çœ²åã¡ãœããã§ãã ãããäœã§ãããã¯ã以äžã§è©³çŽ°ã«æ€èšãããŸãã
ãããã¯ã®NSMethodSignatureãååŸããæ¹æ³
- (NSMethodSignature *)blockMethodSignature { const char *signature = [[self blockSignatureStringCTypes] UTF8String]; return [NSMethodSignature signatureWithObjCTypes:signature]; } - (NSString *)blockSignatureStringCTypes { AXBlockStruct *blockRef = (__bridge AXBlockStruct *)_block; const int flags = blockRef->flags; void *signatureLocation = blockRef->descriptor; signatureLocation += sizeof(unsigned long int); signatureLocation += sizeof(unsigned long int); if (flags & AXBlockFlag_HasCopyDispose) { signatureLocation += sizeof(void(*)(void *dst, void *src)); signatureLocation += sizeof(void (*)(void *src)); } const char *signature = (*(const char **)signatureLocation); return [NSString stringWithUTF8String:signature]; }
ãããã¯ãååŸããããããèšè¿°åãååŸããç®çã®å€ã«ã·ããããŠãããã¯ã®ã·ã°ããã£ïŒconst char *ïŒãååŸããããã䜿çšããŠNSMethodSignatureãäœæããŸãã NSMethodSignatureã¯ãåŒæ°ã®æ°ãšã¿ã€ããæ»ãå€ãªã©ã決å®ããŸãã
è€éã«èŠããŸãããããã©ã°ã®æäœã¯æ··ä¹±ãæããŸãããããã¯ã®ã¿ã€ãã«å¿ããŠããã®çœ²åã¯ããŸããŸãªæ¹æ³ã§èŠã€ããããšãã§ããŸãã ããšãã°ãã°ããŒãã«ãããã¯ã¯ã³ããŒããã³ç Žæ£æ©èœãè¶ ããŠç§»è¡ããå¿ èŠã¯ãããŸããã
ç§ã®ã¯ã©ã¹ã«ã¯ãããã¯ãåŒã³åºãã¡ãœããããªããããforwardInvocationãåŒã³åºãããŸãããã®åã«ãã©ã®ã¿ã€ãã®NSInvocationã圢æããããã調ã¹ãå¿ èŠããããããmethodSignatureForSelectorãåŒã³åºããã_blockMethodSignatureãè¿ãããŸãã
forwardInvocation
- (void)forwardInvocation:(NSInvocation *)anInvocation { [anInvocation setTarget:_block]; if (_beforeInvoke) { _beforeInvoke(anInvocation); } IMP imp = _impBlockInvoke; [anInvocation invokeUsingIMP:imp]; }
ããã®ã³ãŒãã¯éåžžã«æ確ã§ãªããã°ãªããŸããïŒåŒã³åºãã®æ°ããã¿ãŒã²ãããèšå®ããååšããå Žåã¯beforeãããã¯ãåŒã³åºããŸãïŒãã[anInvocation invoke]åŒã³åºãã¯ã©ãã§ããïŒïŒ
ããã¯é»éè¡ã§ãã invokeUsingIMPã¡ãœããã¯ã ããã§èŠã€ããããšãã§ãããã©ã€ããŒãAPIã§ãã
ç¶è¡ããåã«ããºã«ãçµã¿ç«ãŠã
ãããã¯ãããã·ã¯ç¹æ®ãªçŽ æã§ãããåââé¡ã®åŸåã®è§£æ±ºçã«ãŸã£ããé²ããšãèšäºãèªã人ãå°ãªããªããšæããŸãã ãããã£ãŠãã©ãããŒã¯æ¢è£œã®ãœãªã¥ãŒã·ã§ã³ã®ããºã«ãæŸããšç°¡åã«èããããæçµçã«ã¿ã¹ã¯ã®åŸåããœãŒããããŸãã ããã«ãããå°ããªã©ãã¯ã¹ããŠãããäœç³»çãªæ¹æ³ã§è³æãåéã§ããŸãã
èšäºã®åé ã§åŒã³åºãããã¡ãœãããax_lambdaã«ã€ããŠè©±ããŸãããã ããã¯NSObjectã®åãªãã«ããŽãªã§ããã次ã®ããã«èŠããã¡ã€ã³é¢æ°ãåŒã³åºãããã®ã©ãããŒã§ãã
SEL ax_lambda(id obj, id block, NSMutableArray *lambdas);
ã©ãããŒãæžãããŠããçç±ãæããã«ãªã£ãŠãããšæããŸãã ãããŠã1çªç®ãš2çªç®ã®åŒæ°ã§åé¡ãçºçããªãå Žåã3çªç®ã®åŒæ°ã§èããããããŸãã æåã«ã3çªç®ã®åŒæ°ã®å¿ èŠæ§ã«ã€ããŠèª¬æãã次ã«ãã¿ãã¬ã®ã«ããŽãªã³ãŒãã瀺ããŸãã
SEL ax_lambda(id obj, id block, NSMutableArray *lambdas) { SEL selector = ax_generateFreeSelector(obj); AXProxyBlockWithSelf *proxyBlock = [AXProxyBlockWithSelf initWithBlock:block]; [proxyBlock setBeforeInvoke:^(NSInvocation *invocation){ ax_offsetArgInInvocation(invocation); }]; [lambdas addObject:proxyBlock]; IMP imp = imp_implementationWithBlock(proxyBlock); NSString *signatureString = [proxyBlock blockSignatureStringCTypes]; class_addMethod([obj class], selector, imp, [signatureString UTF8String]); return selector; }
ãããäž»ãªæ©èœã§ãããéåžžã«çµã¿ç«ãŠãããããºã«ã§ãã AXProxyBlockWithSelfã¯ã©ã¹ã«ã€ããŠã¯åŸã§æ€èšããŸãããçŸæç¹ã§ã¯ããããããæ³åã®ãšãããããã¯AXProxyBlockã¯ã©ã¹ã®åå«ã§ããããšã«æ³šæããŠãã ããã
ãããã¯ãã¡ãœããã«ããã«ã¯ãã»ã¬ã¯ã¿ãŒãå®è£ ãããã³æåå眲åãå¿ èŠã§ãã å®è£ ã¯ãããã·ãããã¯ããåä¿¡ããããããã·ã¯æåå眲åãæäŸããŸãïŒAXProxyBlockã§ã¯ããã¯ãããã·ããããããã¯ã®çœ²åã§ãããAXProxyBlockWithSelfã§ã¯ç°ãªããŸããããã«ã€ããŠã¯åŸè¿°ããŸãïŒãããããã»ã¬ã¯ã¿ãçæããã®ã¯é£ãããããŸããã ã§ã¯ããªã3çªç®ã®ãã©ã¡ãŒã¿ãŒã§ããïŒ
imp_implementationWithBlockãåŒã³åºããããšããããã¯ã³ããŒïŒBlock_copyïŒãåŒã³åºãããŸãã ãããã¯å ã®copy_helperãã£ãŒã«ãã¯ããããã¯ã®ã³ããŒæ©èœãžã®ãã€ã³ã¿ãŒã§ãã ãã ãããããã·ãããã¯ã«ã¯ãã®æ©èœã¯ãããŸããã voidïŒ*ïŒïŒvoid * dstãvoid * srcïŒã®åœ¢åŒã®ã³ããŒé¢æ°ãäœæããŠããç®çã®çµæãåŸãããšãã§ããŸããã srcã«ã³ããŒããããªããžã§ã¯ããæ¥ãŸãããããã¯ç§ã®ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã§ã¯ãããŸããã ãããã£ãŠãimp_implementationWithBlockãåŒã³åºããŠããproxyBlockãªããžã§ã¯ãã®åç §ã«ãŠã³ãã¯å¢å ããŸããïŒé¢æ°ã®çµäºåŸã«proxyBlockã¯ç Žæ£ãããŸãïŒã ãããé²ãããã«ãå éšåç §ã«ãŠã³ããå¢ããã³ã¬ã¯ã·ã§ã³ã䜿çšããŸãã ãããã¯ã®å¯¿åœã¯ããããä¿åããã³ã¬ã¯ã·ã§ã³ã®å¯¿åœã«äŸåããããšãããããŸãã ã«ããŽãªãŒã®å Žåããããã¯ã®å¯¿åœã¯ææè ã®å¯¿åœã«ãã£ãŠå¶éãããŸãã
AXLambda.h
SEL ax_lambda(id obj, id block, NSMutableArray *lambdas); @interface NSObject (AX_Lambda) - (SEL)ax_lambda:(id)block; @end
AXLambda.m
static char kAX_NSObjectAssociatedObjectKey; @interface NSObject (_AX_Lambda) @property (copy, nonatomic) NSMutableArray *ax_lambdas; @end @implementation NSObject (_AX_Lambda) @dynamic ax_lambdas; - (void)setAx_lambdas:(NSMutableArray *)lambdas { objc_setAssociatedObject(self, &kAX_NSObjectAssociatedObjectKey, lambdas, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSMutableArray *)ax_lambdas { NSMutableArray *marrey = objc_getAssociatedObject(self, &kAX_NSObjectAssociatedObjectKey); if (marrey == nil) { self.ax_lambdas = [NSMutableArray array]; } return objc_getAssociatedObject(self, &kAX_NSObjectAssociatedObjectKey); } @end @implementation NSObject (AX_Lambda) - (SEL)ax_lambda:(id)block { return ax_lambda(self, block, self.ax_lambdas); } @end
ããŠãSEL ax_lambdaã§äœ¿çšãããé¢æ°ïŒid objãidãããã¯ãNSMutableArray * lambdasïŒ;
SEL ax_generateFreeSelectorïŒid objïŒ
SEL ax_generateFreeSelector(id obj) { SEL selector; NSMutableString *mstring = [NSMutableString string]; do { [mstring setString:@"ax_rundom_selector"]; u_int32_t rand = arc4random_uniform(UINT32_MAX); [mstring appendFormat:@"%zd", rand]; selector = NSSelectorFromString(mstring); } while ([obj respondsToSelector:selector]); return selector; }
void ax_offsetArgInInvocationïŒNSInvocation *åŒã³åºãïŒ
void ax_offsetArgInInvocation(NSInvocation *invocation) { void *foo = malloc(sizeof(void*)); NSInteger arguments = [[invocation methodSignature] numberOfArguments]; for (NSInteger i = 1; i < arguments-1; i++) { //i = 0 is self [invocation getArgument:foo atIndex:i+1]; [invocation setArgument:foo atIndex:i]; } free(foo); }
StringWithFormatãšNSArrayãçµã¿åãããŠNSMethodSignatureãç解ãã
次ã®ããŒããå§ããåã«ãNSInvocationãšNSMethodSignatureã®åºæ¬çãªç解ãå¿ èŠã§ãã ç§ã¯ãããå¥ã®èšäºã§åé¢ããããšãèããŸããããå®éã«æ·±ãæãäžããªããã°ãèšäºã¯èå³æ·±ãã·ã³ãã«ãªãã®ã«ãªããŸãïŒå ·äœçãªäŸãåæãããšïŒããããã»ã©å€§ããã¯ãªããšããçµè«ã«éããŸããã ããã§ç§ã¯ããã§ããã«ã€ããŠæžãããšã«ããŸããã
次ã®ããã«ããã©ãŒããããšåŒæ°ã®é åããæååãçæããã¡ãœãããå¿ èŠã§ããïŒ
NSString *format = @"%@, foo:%@, hello%@"; NSArray *input = @[@(12), @(13), @" world"]; NSString *result = [NSString ax_stringWithFormat:format array:input]; //result â @"12, foo:13, hello world"
æ®å¿µãªãããSOã§èŠã€ããã¡ãœããã¯æ©èœããŸããã§ããïŒ first ã second ïŒã ããããARCã§ããããæ£ãã䜿çšããããšããŸããã§ããïŒæåããæ¹ã¯æžãçããŠãã ããïŒããäœæ¥ããŒãžã§ã³ãå¿ èŠãªãããå®è£ ãäœæããŸããã
ãã€ã³ã¿ãŒãŸãã¯å€æã§ã©ãŠã³ããè¡ãããšãªãããœãªã¥ãŒã·ã§ã³ã¯ã¡ãœããã®åçã«å®å šã«åºã¥ããŠããŸãã
ã¡ãœããã®æçµåœ¢åŒã¯æ¬¡ã®ããã«ãªããŸãã
+ (instancetype)ax_stringWithFormat:(NSString *)format array:(NSArray *)arguments;
圢åŒãšãã©ã¡ãŒã¿ã«ãã£ãŠæååãäœæããæšæºçãªæ¹æ³ã¯æ¬¡ã®ãšããã§ã
- (instancetype)initWithFormat:(NSString *)format arguments:(va_list)argList NS_FORMAT_FUNCTION(1,0);
ãããã䜿çšããã«ã¯ïŒããã³åé¡èªäœïŒãva_listãäœæããå¿ èŠããããŸãïŒva_listãšã¯äœã§ããïŒãŸãã䜿çšæ¹æ³ ïŒã
次ã®æ¹æ³ã¯çŽ æŽããã
+ïŒinstancetypeïŒax_stringïŒïŒNSString *ïŒformatã...
+ (instancetype)ax_string:(NSString *)format, ... { va_list list; va_start(list, format); NSString *str = [[NSString alloc] initWithFormat:format arguments:list]; va_end(list); return str; }
ããã§ã®åé¡ã¯ãNSArrayããã®åŒæ°ã䜿çšããŠåŒã³åºãæ¹æ³ã§ãã
NSInvocationã¯ããªããžã§ã¯ãéããã³/ãŸãã¯ã¢ããªã±ãŒã·ã§ã³éã§ã¡ãã»ãŒãžãä¿åããã³è»¢éããããã«äœ¿çšããããªããžã§ã¯ãã§ãã
ãã ããNSInvocationãäœæãããšãã¯ãNSMethodSignatureãå¿ èŠã§ãã
NSMethodSignatureã䜿çšãããšãã¡ãœãããåãåãåŒæ°ã®æ°ãåŒæ°ã®åããªãã»ãããæ»ãå€ã®åã決å®ã§ããŸã ã ããã¥ã¡ã³ãããã®çºèšã¯ããã«ã€ããŠéåžžã«è«ççã«èŠããŸã
NSInvocationã¯ãå¯å€æ°ã®åŒæ°ãŸãã¯ãŠããªã³åŒæ°ã䜿çšããã¡ãœããã®åŒã³åºãããµããŒãããŠããŸããã
çµå±ã®ãšãããåŒæ°ã®æ°ãå¯å€ã®é¢æ°/ã¡ãœããã«æž¡ãããåŒæ°ã®æ°ãšã¿ã€ãã¯äžæã§ãã
ãããŠãããªãããŸã ç¥ã£ãŠãããªãïŒ é»è©±ããåã«ç§èªèº«ããã®æ å ±ãç¥ã£ãŠãããïŒ ãããŠããã®å Žåãã¡ãœããã¯äŸãã°4ã€ã®åŒæ°ãåããé¢æ°ã¯å¯å€æ°ã®åŒæ°ãåããããããŸããããããã¯åäœããŸãã
NSMethodSignatureã¯ãäžèšã®ãã¹ãŠã®æ å ±ãèªåã§æå®ããå Žåãçæããã眲åãéããŠäœæã§ããŸãã NSArrayã«ã¯ããã€ã³ã¿ãŒãšããã€ã³ã¿ãŒã®ãµã€ãºã«ãããã¹ãŠã®ãã©ã¡ãŒã¿ãŒã®ãªãã»ããã®ã¿ãå«ãŸããŠããããããã¹ãŠãéåžžã«åçŽã§ãã ãã§ã«æžããããã«ãã¡ãœããã«ã¯selfãš_cmdã䜿çšã§ããŸãããããã¯æé»çã«ã¡ãœããã«æž¡ãããããã§ãã
+ïŒNSMethodSignature *ïŒax_generateSignatureForArgumentsïŒïŒNSArray *ïŒåŒæ°
+ (NSMethodSignature *)ax_generateSignatureForArguments:(NSArray *)arguments { NSInteger count = [arguments count]; NSInteger sizeptr = sizeof(void *); NSInteger sumArgInvoke = count + 3; // self + _cmd + NSInteger offsetReturnType = sumArgInvoke * sizeptr; NSMutableString *mstring = [[NSMutableString alloc] init]; [mstring appendFormat:@"@%zd@0:%zd", offsetReturnType, sizeptr]; for (NSInteger i = 2; i < sumArgInvoke; i++) { [mstring appendFormat:@"@%zd", sizeptr * i]; } return [NSMethodSignature signatureWithObjCTypes:[mstring UTF8String]]; }
ããã§äœãèµ·ãã£ãŠãããã«ã€ããŠå°ã話ã䟡å€ããããŸãã æåã«ãããã§ã³ãŒãã£ã³ã°ã®ã¿ã€ãã調ã¹ãå¿ èŠããããŸã ã
ãããŠä»ãé çªã«ãããªããããŒãã«ãèŠãããšãæ¬åœã«é¡ã£ãŠããŸãã
眲åã®æåã®å Žæã¯æ»ãå€ã®åãšãã®ãªãã»ããã§ãïŒæ»ãå€ã®åã¯ãã¹ãŠã®åŒæ°ã®åŸã«ãããããæ倧ã®ãªãã»ããããããŸãããæåã«æžã蟌ãŸããŸãïŒã sizeofïŒvoid *ïŒã8ã§ããã3ã€ã®åŒæ°ã®é åã§ãããšããŸãã ãã ããself + _cmd +æž¡ããã圢åŒãå«ããŠã6ã€ã®åŒæ°ãååŸããŸãã 6x8 = 48
@ 48
ãã®åŸãselfããã³_cmdã«åŸããŸãã åŒæ°ã®äžã§selfãæåã«æ¥ãã®ã§ã
@ 48 @ 0ïŒ8
次ã«ãã©ãŒããã
@ 48 @ 0ïŒ8 @ 16
ãšåŒæ°
@ 48 @ 0ïŒ8 @ 16 @ 24 @ 32 @ 40
眲åãã§ããã®ã§ãNSInvocationã䜿çšã§ããŸã
+ïŒinstancetypeïŒax_stringWithFormatïŒïŒNSString *ïŒformat arrayïŒïŒNSArray *ïŒarrayArguments
+ (instancetype)ax_stringWithFormat:(NSString *)format array:(NSArray *)arrayArguments { NSMethodSignature *methodSignature = [self ax_generateSignatureForArguments:arrayArguments]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; [invocation setTarget:self]; [invocation setSelector:@selector(ax_string:)]; [invocation setArgument:&format atIndex:2]; for (NSInteger i = 0; i < [arrayArguments count]; i++) { id obj = arrayArguments[i]; [invocation setArgument:(&obj) atIndex:i+3]; } [invocation invoke]; __autoreleasing NSString *string; [invocation getReturnValue:&string]; return string; }
ãããŠä»ãäžèšã®ã¡ãœããããããã«å€æŽãããšã+ïŒinstancetypeïŒax_stringã¡ãœãããåé€ã§ããŸãïŒïŒNSString *ïŒformatã...
ãã¿ãã¬ã®äžã®å®å
šãªã³ãŒã
+ (instancetype)ax_stringWithFormat:(NSString *)format array:(NSArray *)arrayArguments { NSMethodSignature *methodSignature = [self ax_generateSignatureForArguments:arrayArguments]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; [invocation setTarget:self]; [invocation setSelector:@selector(stringWithFormat:)]; [invocation setArgument:&format atIndex:2]; for (NSInteger i = 0; i < [arrayArguments count]; i++) { id obj = arrayArguments[i]; [invocation setArgument:(&obj) atIndex:i+3]; } [invocation invoke]; __autoreleasing NSString *string; [invocation getReturnValue:&string]; return string; } //https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html + (NSMethodSignature *)ax_generateSignatureForArguments:(NSArray *)arguments { NSInteger count = [arguments count]; NSInteger sizeptr = sizeof(void *); NSInteger sumArgInvoke = count + 3; //self + _cmd + (NSString *)format NSInteger offsetReturnType = sumArgInvoke * sizeptr; NSMutableString *mstring = [[NSMutableString alloc] init]; [mstring appendFormat:@"@%zd@0:%zd", offsetReturnType, sizeptr]; for (NSInteger i = 2; i < sumArgInvoke; i++) { [mstring appendFormat:@"@%zd", sizeptr * i]; } return [NSMethodSignature signatureWithObjCTypes:[mstring UTF8String]]; }
åé¡ã®åŸåã®è§£æ±ºç-æ°ä»ãããªããããã¯ã«ããã«1ã€ã®åŒæ°ãè¿œå ããæ¹æ³ã¯ïŒ
ãããã¯ãåŒã³åºãããç¬éã®ã€ã³ã¿ãŒã»ãããšåŒæ°ã®ãªãã»ãããèæ ®ãããŸããã ãã®ã¢ããªã±ãŒã·ã§ã³ã®ã¢ã€ãã¢ãšå°ããªãã¥ã¢ã³ã¹ãé©çšããããã®ã³ãŒããæ€èšãããŸããã ãã ããå®äºã劚ããåé¡ãæ®ã£ãŠããŸããã
imp_implementationWithBlockã§åãå ¥ãããããããã¯ã¯ãæåã«ææè ã®åŒæ°ãåãå¿ èŠããããŸãã ax_lambdaé¢æ°ã®å ¥åãããã¯ã®çœ²åã¯æå³ãã眲åãšã¯ç°ãªããåŒæ°ã¯NSInvocationã«å®å šã«ééã£ãŠè»¢éãããããšãããããŸããã
AXProxyBlockWithSelfã¯ã©ã¹ã¯ããããã·ããããããã¯ã®çœ²åãããçŽããè¿œå ã®æåã®åŒæ°ãè¿œå ããŸãã ãããã£ãŠããããã·ãããã¯åŒã³åºãã¯æ£ããåŒæ°ã§å®äºããæåã®åŒæ°ã¯ãããã¯åŒã³åºãã®åã«ãã§ã«ã·ãããããŠããŸãã
ã¡ãœãããæžãæããå¿ èŠããããŸã-ïŒNSString *ïŒblockSignatureStringCTypes
-ïŒNSString *ïŒblockSignatureStringCTypes
- (NSString *)blockSignatureStringCTypes { NSString *signature = [super blockSignatureStringCTypes]; NSString *unformatObject = [signature ax_unformatDec]; NSString *formatNewSignature = [self addSelfToFormat:unformatObject]; NSArray *byteSignature = [signature ax_numbers]; NSArray *byteNewSignature = [self changeByteSignature:byteSignature]; return [NSString ax_stringWithFormat:formatNewSignature array:byteNewSignature]; }
ãã®ãããåŒæ°ã®åãšãªãã»ãããæ»ãå€ã®åãªã©ãå«ããããã¯çœ²åããããŸãã
è¿œå ã®åŒæ°ã眲åã«æ¿å ¥ããåŒæ°ãã·ããããå¿ èŠããããŸãã
眲åæåå圢åŒã®åæ圢åŒãååŸããŸã
- (NSString *)ax_unformatDec { NSCharacterSet *characterSet = [NSCharacterSet decimalDigitCharacterSet]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"length > 0"]; NSArray *separated = [[self componentsSeparatedByCharactersInSet:characterSet] filteredArrayUsingPredicate:predicate]; NSString *format = [separated componentsJoinedByString:@"%@"]; if ([[self lastSubstring] isEqualToString:[format lastSubstring]] ) { return format; } else { return [format stringByAppendingString:@"%@"]; } } - (NSString *)lastSubstring { NSInteger lastIndex = [self length] - 1; return [self substringFromIndex:lastIndex]; }
次ã«ãããã§ã³ãŒãã£ã³ã°ã®ã¿ã€ãã確èªããå¿ èŠããããŸã ã
åŒæ°\ "ææè
\"ãæåã®å Žæã«è¿œå ããŸã
- (NSString *)addSelfToFormat:(NSString *)format { NSMutableArray *marray = [[format componentsSeparatedByString:@"?"] mutableCopy]; [marray insertObject:@"?%@@" atIndex:1]; return [marray componentsJoinedByString:@""]; }
åŒã³åºãNSArrayåŒæ°ãªãã»ãããååŸããŸã
- (NSArray *)ax_numbers { NSString *pattern = @"\\d+"; NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:nil]; NSRange fullRange = NSMakeRange(0, [self length]); NSArray *matches = [regex matchesInString:self options:NSMatchingReportProgress range:fullRange]; NSMutableArray *numbers = [NSMutableArray array]; for (NSTextCheckingResult *checkingResult in matches) { NSRange range = [checkingResult range]; NSString *numberStr = [self substringWithRange:range]; NSNumber *number = @([numberStr integerValue]); [numbers addObject:number]; } return numbers; }
è¿œå ãããåŒæ°ãèæ
®ããŠãåŒæ°ã®ãªãã»ãããæ°ããå€ã«å€æŽããŸã
- (NSArray *)changeByteSignature:(NSArray *)byteSignature { NSInteger value = sizeof(void *); NSMutableArray *marray = [NSMutableArray array]; for (NSNumber *number in byteSignature) { NSInteger offset = [number integerValue] + value; [marray addObject:@(offset)]; } [marray insertObject:@0 atIndex:1]; return marray; }
æåŸã«ãæ°ããæåå圢åŒãšæ°ãããªãã»ãããæã€NSArrayã䜿çšããŠãæ°ãã眲åãäœæããŸãã ãããã£ãŠãå®è£ ãåŒã³åºããããšãææè ã¯æåã®åŒæ°ãšããŠããã¥ã¡ã³ãã«åŸã£ãŠè»¢éãããã€ã³ã¿ãŒã»ããã®ããã«ã·ãããããå ã®ãããã¯ãåŒã³åºãããŸãã
å®å šãªã³ãŒãã¯ãã¡ãã ããã¯åãªãå®éšã§ããããããžã§ã¯ãã§äœ¿çšããããã«ãã®ã³ãŒããèšè¿°ããããšã¯æã¿ãŸããã§ããã ããããç§ã¯ãã®ããžãã¹ãæåè£ã«å®äºã§ããããšãå¬ããæããŸãã ãŸããSOã§NSArrayã䜿çšããŠæååãçæããããã®ãœãªã¥ãŒã·ã§ã³ãã¬ã€ã¢ãŠãããããšã§ã誰ããå©ããããšãã§ããããšãå¬ããã§ãã
ç解ãããã圢ã§è³æãäŒãããããã¯ã«åå²ã§ããããšãé¡ã£ãŠããŸãã