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
//<nil>
//(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

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,715评论 0 9
  • 我们常常会听说 Objective-C 是一门动态语言,那么这个「动态」表现在哪呢?我想最主要的表现就是 Obje...
    Ethan_Struggle阅读 2,195评论 0 7
  • 转载:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麦子阅读 733评论 0 2
  • 本文转载自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex阅读 761评论 0 1
  • 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的...
    lylaut阅读 800评论 0 4