RAC宏分析2:获取可变参
2017-07-05 本文已影响55人
大刘
把可变参装入数组
+ (NSMutableArray *)arrayWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION {
NSMutableArray *array = [NSMutableArray array];
va_list argList;
if (firstObj) {
[array addObject:firstObj];
va_start(argList, firstObj);
id temp;
while ((temp = va_arg(argList, id))) {
[array addObject:temp];
}
}
va_end(argList);
return array;
}
rac_liftSelector:withSignals:....
我们仿写一个:
//
// RACSignal.h
// Created by liuweizhen on 2017/6/15.
// Copyright © 2017年 刘威振. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface RACSignal : NSObject
@property (nonatomic, copy) NSString *name;
@end
#import "RACSignal.h"
@implementation RACSignal
@end
//
// NSObject+RACLifting.h
// Created by liuweizhen on 2017/6/15.
// Copyright © 2017年 刘威振. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RACSignal.h"
@interface NSObject (RACLifting)
- (void)rac_liftSelector:(SEL)selector withSignals:(RACSignal *)firstSignal, ... NS_REQUIRES_NIL_TERMINATION;
- (void)rac_liftSelector:(SEL)selector withSignalsFromArray:(NSArray *)signals;
@end
//
// NSObject+RACLifting.m
// VA_LIST
//
// Created by liuweizhen on 2017/6/15.
// Copyright © 2017年 刘威振. All rights reserved.
//
#import "NSObject+RACLifting.h"
@implementation NSObject (RACLifting)
- (void)rac_liftSelector:(SEL)selector withSignals:(RACSignal *)firstSignal, ... {
NSCParameterAssert(firstSignal != nil);
NSMutableArray *signals = [NSMutableArray array];
va_list args;
va_start(args, firstSignal); // 指向第一个可变参
for (id currentSignal = firstSignal; currentSignal != nil; currentSignal = va_arg(args, id)) {
NSCAssert([currentSignal isKindOfClass:RACSignal.class], @"Argument %@ is not a RACSignal", currentSignal);
[signals addObject:currentSignal];
}
va_end(args);
[self rac_liftSelector:selector withSignalsFromArray:signals];
}
- (void)rac_liftSelector:(SEL)selector withSignalsFromArray:(NSArray *)signals {
NSCParameterAssert(signals != nil);
NSCParameterAssert(signals.count > 0);
// 方法签名
NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector];
NSCAssert(methodSignature != nil, @"%@ does not respond to %@", self, NSStringFromSelector(selector));
NSUInteger numberOfArguments __attribute__((unused)) = methodSignature.numberOfArguments - 2; // From Apple: There are always at least two arguments, because an NSMethodSignature object includes the implicit arguments self and _cmd, which are the first two arguments passed to every method implementation.
NSCAssert(numberOfArguments == signals.count, @"Wrong number of signals for %@ (expected %lu, got %lu)", NSStringFromSelector(selector), (unsigned long)numberOfArguments, (unsigned long)signals.count);
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
invocation.selector = selector;
for (NSInteger i = 0; i < signals.count; i++) {
NSInteger j = i + 2;
RACSignal *signal = signals[i];
[invocation setArgument:&signal atIndex:j];
}
//
// RACSignal *signal0 = signals[0];
// RACSignal *signal1 = signals[1];
// RACSignal *signal2 = signals[2];
// // 前两个被selector和target占用, 所以从2开始
// [invocation setArgument:&signal0 atIndex:2];
// [invocation setArgument:&signal1 atIndex:3];
// [invocation setArgument:&signal2 atIndex:4];
// invocation.target = self;
[invocation invokeWithTarget:self];
}
@end