RacInvocation消息调用

objc_getAssociatedObject
objc_setAssociatedObject

objc_allocateClassPair 新注册一个类,为类添加方法
objc_registerClassPair
_objc_msgForward
objc_allocateProtocol
objc_registerProtocol
objc_getProtocol
objc_getMetaClass
_objc_msgForward_stret
objc_msgSend

object_getClass 获取obj的isa指向 char*转化Class
object_setClass 强制设置obj的isa指向

class_getInstanceMethod 获取类的实例方法
class_getSuperclass 获取类的父类
class_replaceMethod 替换某个类的方法为新的实现

class_addMethod
Adds a new method to a class with a given name and implementation.
class_addMethod will add an override of a superclass's implementation, but will not replace an existing implementation in this class. To change an existing implementation, use method_setImplementation.

cls 
    The class to which to add a method.
name    
    A selector that specifies the name of the method being added.

class_respondsToSelector
class_getMethodImplementation
class_isMetaClass
class_addProtocol

method_getImplementation
method_getTypeEncoding
method_exchangeImplementations

protocol_addMethodDescription
protocol_copyMethodDescriptionList

Sel
Method
Protocol
Class
NSMethodSignature

子类/重写几个方法

1、RAC的Selector实现原理
创建一个全新的类型; 交换下面的几个方法:
forwardInvocation
respondsToSelector
class
methodSignatureForSelector

2、系统的KVO的实现原理
子类;

3、RAC的swizzleDeallocIfNeeded实现原理
方法交换;

4、RAC的KVO

支持同时实现RAC的SwizzleSelector和RACObserve,这么用没问题。
但是dealloc的SwizzleSelector和dealloc的swizzleDeallocIfNeeded同时实现会发生crash!

[[self rac_signalForSelector:@selector(setKvoValue:)] subscribeNext:^(RACTuple * _Nullable x) {
    NSLog(@"11111  %@", x);
}];
[[RACKVOTrampoline alloc] initWithTarget:self observer:self  keyPath:@keypath(self.kvoValue) options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(id target, id observer, NSDictionary *change) {
    NSLog(@"22222    %@,%@, %@", change, target, observer);
}];

Method method = class_getInstanceMethod(self.class, @selector(timerfirep:));
char const objctypes = method_getTypeEncoding(method);
//[NSMethodSignature signatureWithObjCTypes:]: type signature is NULL.'
NSMethodSignature
msign= // [self methodSignatureForSelector:@selector(timerfirep:)];
// [NSMethodSignature methodSignatureForSelector:@selector(timerfirep:)];
//[NSMethodSignature instanceMethodSignatureForSelector:@selector(timerfirep:)];
[NSMethodSignature signatureWithObjCTypes:objctypes];
NSInvocation*ivok= [NSInvocation invocationWithMethodSignature:msign];
ivok.selector =@selector(timerfirep:);
ivok.target=self;
[ivok setArgument:@"aa" atIndex:2];
[ivok invoke];
__unsafe_unretained id aa;
[ivok getReturnValue:&aa];

5、RacBlockTrampoline 与 NSInvocation

performSelector
参数限制:
1、支持最多两个参数。

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

2、返回类型限制:
如果aSelector返回c基本数据类型(非id对象数据类型), 则此调用会崩溃。 入口参数也只能是id类型。

3、libDispatch库、如果perferm到主线程提交, 则由runloop+timer (runloop组成:每一个mode的item有(source、timer 、observer组成))实现。

NSInvocation

应用1; RACBlockTrampoline----Block不支持:基本数据类型的参数和返回值

  • (__kindof RACStream *)reduceEach:(id (^)())reduceBlock {
    NSCParameterAssert(reduceBlock != nil);

    __weak RACStream *stream attribute((unused)) = self;
    return [[self map:^(RACTuple *t) {
    NSCAssert([t isKindOfClass:RACTuple.class], @"Value from stream %@ is not a tuple: %@", stream, t);

        /// Block不支持:基本数据类型的参数和返回值
    return [RACBlockTrampoline invokeBlock:reduceBlock withArguments:t];
}] setNameWithFormat:@"[%@] -reduceEach:", self.name];

}

  • (id)invokeWithArguments:(RACTuple *)arguments {
    SEL selector = [self selectorForArgumentCount:arguments.count];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:selector]];
    invocation.selector = selector;
    invocation.target = self;

    for (NSUInteger i = 0; i < arguments.count; i++) {
    id arg = arguments[i];
    NSInteger argIndex = (NSInteger)(i + 2);
    [invocation setArgument:&arg atIndex:argIndex];
    }

    [invocation invoke];

    __unsafe_unretained id returnVal;
    [invocation getReturnValue:&returnVal];
    return returnVal;
    }

应用2: ----支持基本数据类型的参数

[[self rac_signalForSelector:@selector(intValue1:float2:char:)] subscribeNext:^(RACTuple * _Nullable x) {
    NSLog(@"111->  %@" ,  x);
} error:^(NSError * _Nullable error) {
    NSLog(@"222->: %@" ,error );
} completed:^{
    NSLog(@"completed!!");
}];

static BOOL RACForwardInvocation(id self, NSInvocation *invocation) {
SEL aliasSelector = RACAliasForSelector(invocation.selector);
RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);

Class class = object_getClass(invocation.target);
BOOL respondsToAlias = [class instancesRespondToSelector:aliasSelector];
if (respondsToAlias) {
    invocation.selector = aliasSelector;
    [invocation invoke];
}

if (subject == nil) return respondsToAlias;
        ///支持基本数据类型的参数
[subject sendNext:invocation.rac_argumentsTuple];
return YES;

}

  • (RACTuple *)rac_argumentsTuple {
    NSUInteger numberOfArguments = self.methodSignature.numberOfArguments;
    NSMutableArray *argumentsArray = [NSMutableArray arrayWithCapacity:numberOfArguments - 2];
    for (NSUInteger index = 2; index < numberOfArguments; index++) {
        /// Rac实现的自动转化类型 -----NSInvocation+RACTypeParsing.h


//d, f, Q, I 等。 。CGFloat对应Double 转化过程rac_argumentAtIndex
//    NSLog(@"%s, %s, %s, %s",  @encode(CGFloat),  @encode(float),  @encode(NSUInteger), @encode(unsigned int));




    [argumentsArray addObject:[self rac_argumentAtIndex:index] ?: RACTupleNil.tupleNil];
}

return [RACTuple tupleWithObjectsFromArray:argumentsArray];

}

应用3: -------

//  methodSignature 的numberOfArguments已经包括了target和selector了的个数了
NSMethodSignature *methodSignature = [self methodSignatureForSelector:@selector(intValue1:float2:char:)] ;

NSInvocation*invocation  = [NSInvocation invocationWithMethodSignature:methodSignature];
RACTuple *argumentTuple= [RACTuple tupleWithObjects:@"1",@"1.2",@"122", nil];

// Rac实现的自动转化类型
 invocation.rac_argumentsTuple = argumentTuple;

// 自己实现需要这样 ---
//    基本数据类型:char,int,short,long,long long,unsigned char, unsigned int, unsigned short, unsigned long, unsigned long long,float, double, bool, char *
//    block,id ,Class类型
//    NSValue类型

int intValue1 = [argumentTuple[0] intValue];
float floatValue = [argumentTuple[1] floatValue];
const char *charValue = [argumentTuple[2] UTF8String];
[invocation setArgument:&(intValue1) atIndex:2];
[invocation setArgument:&(floatValue) atIndex:3];
[invocation setArgument:&charValue atIndex:4];

// (lldb) po invocation.selector
//
//(lldb) po invocation.target
//nil
//此时target和selector还都是空。所以要赋值
invocation.selector =@selector(intValue1:float2:char:);
invocation.target=self;
[invocation invoke];

__unsafe_unretained id aa;
// Rac实现基本数据类型的转换
aa =[invocation rac_returnValue];

// 自己实现需要这样 ---
//    基本数据类型:char,int,short,long,long long,unsigned char, unsigned int, unsigned short, unsigned long, unsigned long long,float, double, bool, char *
//    block,id ,Class类型
//    NSValue类型
int aReturnValue = 0;
[invocation getReturnValue:&aReturnValue];

NSLog(@"%@ , %d", aa, aReturnValue);

-(int )intValue1:(int )int1 float2:(float)float2 char:(char *)char3 {
NSLog(@"NSInvocation调用成功:%d , %f, %s ", int1, float2, char3);
return 1;
}

void 类型:void
block类型:void (^)(void)
对象类型:id,Class,
基本数据类型:char,int,short,long,long long(NSInteger),unsigned char, unsigned int, unsigned short, unsigned long, unsigned long long(NSUInteger),float, double(CGFloat), bool, char *
数值类型 8种类型:需要用NSValue转换。CGPoint,CGVector,CGSize,CGRect,CGAffineTransform,UIEdgeInsets, NSDirectionalEdgeInsets,UIOffset

SEL sel =@selector(intValue1:cgfloat2:char:cgpoint:);
NSMethodSignature *signature = [self methodSignatureForSelector:sel ];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature ];
invocation.selector = sel   ;

invocation.rac_argumentsTuple = RACTuplePack(@"12345",@(1.2),@"12122",[NSValue valueWithCGPoint:CGPointMake(12, 122)]);
[invocation invokeWithTarget:self];

NSValue*pointValue= [invocation rac_returnValue];
NSLog(@"%@",NSStringFromCGPoint(    [pointValue CGPointValue]));

-(CGPoint )intValue1:(int )int1 cgfloat2:(CGFloat)float2 char:(const char *)char3 cgpoint:(CGPoint)point4 {
NSLog(@"NSInvocation调用成功:%d , %f, %s , %@", int1, float2, char3, NSStringFromCGPoint(point4));
return CGPointMake(100, 100);
}

  • (void)rac_setArgument:(id)object atIndex:(NSUInteger)index {

define PULL_AND_SET(type, selector) \

do { \
    type val = [object selector]; \
    [self setArgument:&val atIndex:(NSInteger)index]; \
} while (0)

const char *argType = [self.methodSignature getArgumentTypeAtIndex:index];
// Skip const type qualifier.
if (argType[0] == 'r') {
    argType++;
}

if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) {
    [self setArgument:&object atIndex:(NSInteger)index];
} else if (strcmp(argType, @encode(char)) == 0) {
    PULL_AND_SET(char, charValue);
} else if (strcmp(argType, @encode(int)) == 0) {
    PULL_AND_SET(int, intValue);
} else if (strcmp(argType, @encode(short)) == 0) {
    PULL_AND_SET(short, shortValue);
} else if (strcmp(argType, @encode(long)) == 0) {
    PULL_AND_SET(long, longValue);
} else if (strcmp(argType, @encode(long long)) == 0) {
    PULL_AND_SET(long long, longLongValue);
} else if (strcmp(argType, @encode(unsigned char)) == 0) {
    PULL_AND_SET(unsigned char, unsignedCharValue);
} else if (strcmp(argType, @encode(unsigned int)) == 0) {
    PULL_AND_SET(unsigned int, unsignedIntValue);
} else if (strcmp(argType, @encode(unsigned short)) == 0) {
    PULL_AND_SET(unsigned short, unsignedShortValue);
} else if (strcmp(argType, @encode(unsigned long)) == 0) {
    PULL_AND_SET(unsigned long, unsignedLongValue);
} else if (strcmp(argType, @encode(unsigned long long)) == 0) {
    PULL_AND_SET(unsigned long long, unsignedLongLongValue);
} else if (strcmp(argType, @encode(float)) == 0) {
    PULL_AND_SET(float, floatValue);
} else if (strcmp(argType, @encode(double)) == 0) {
    PULL_AND_SET(double, doubleValue);
} else if (strcmp(argType, @encode(BOOL)) == 0) {
    PULL_AND_SET(BOOL, boolValue);
} else if (strcmp(argType, @encode(char *)) == 0) {
    const char *cString = [object UTF8String];
    [self setArgument:&cString atIndex:(NSInteger)index];
    [self retainArguments];
} else if (strcmp(argType, @encode(void (^)(void))) == 0) {
    [self setArgument:&object atIndex:(NSInteger)index];
} else {

// CGPoint,CGRect这些类型用NSValue进行参数传入
NSCParameterAssert([object isKindOfClass:NSValue.class]);

    NSUInteger valueSize = 0;
    NSGetSizeAndAlignment([object objCType], &valueSize, NULL);

if DEBUG

    NSUInteger argSize = 0;
    NSGetSizeAndAlignment(argType, &argSize, NULL);
    NSCAssert(valueSize == argSize, @"Value size does not match argument size in -rac_setArgument: %@ atIndex: %lu", object, (unsigned long)index);

endif

    unsigned char valueBytes[valueSize];
    [object getValue:valueBytes];

    [self setArgument:valueBytes atIndex:(NSInteger)index];
}

undef PULL_AND_SET

}

你可能感兴趣的:(RacInvocation消息调用)