runtime之动态添加方法
2018-03-06 本文已影响0人
Just丶Go
实际上是解释消息传递的机制中的一个动态解析过程(新增)
需求:runtime 动态添加方法处理调用一个未实现的方法 和 去除报错。
案例代码
//
// UsrModel.h
// Runtime_testing
//
// Created by ZTL_Sui on 2018/2/28.
// Copyright © 2018年 ZTL_Sui. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface UsrModel : NSObject
- (NSString *)run:(NSNumber *)meter;
- (NSNumber *)eat;
@end
IMP
//
// UsrModel.m
// Runtime_testing
//
// Created by ZTL_Sui on 2018/2/28.
// Copyright © 2018年 ZTL_Sui. All rights reserved.
//
#import "UsrModel.h"
#import <objc/runtime.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincomplete-implementation"
@implementation UsrModel
#pragma clang diagnostie pop
/// 此处方法可以改写为OC实例方法
NSString * _c_method (id self, SEL _cmd, NSNumber *meter)
{
NSLog(@"跑了 %@米", meter);
return @"333";
}
/**
* OC底层是通过消息机制来进行消息发送的,而不是静态语言的函数调用(改)。
* 向一个对象发送消息的处理流程
-->对象接收到消息
-->查看缓存中是否有匹配的方法,如果有则响应,否则继续
-->查看对象的类对象的方法列表(method list)中是否有匹配方法,如果有则响应,否则继续
-->查看对象的父类的缓存和方法列表中是否有匹配方法,如果有则响应,没有继续
-->进入动态解析 +(BOOL)resolveInstanceMethod:(SEL)sel;+(BOOL)resolveClassMethod:(SEL)sel,如果有指定的动态解析方法则响应,否则继续<PS:resolveInstanceMethod解析对象方法;resolveClassMethod解析类方法>
-->进入消息重定向 -(id)forwardingTargetForSelector:(SEL)aSelector;如果有指定消息接收对象则响应,否则继续
-->开始消息转发 -(void)forwardInvocation:(NSInvocation *)anInvocation;如果有指定转发对象则响应,否则抛出异常
*
**/
/// 下面我们着重实现动态解析的过程
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == NSSelectorFromString(@"run:"))
{
/// type: 解释 "s@:@" \
/// s@:表示函数返回值;其中s表示返回字符串类型,v表示void,i表示int,以此类推;
///返回值类型后面的@表示参数,有几个参数就有几个@;
class_addMethod(self, sel, (IMP)_c_method, "s@:@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
SEL name = [anInvocation selector];
NSLog(@" >> forwardInvocation for selector %@", NSStringFromSelector(name));
UsrModel * proxy = [[UsrModel alloc] init];
if ([proxy respondsToSelector:name]) {
[anInvocation invokeWithTarget:proxy];
}
else {
[super forwardInvocation:anInvocation];
}
}
+(BOOL)resolveClassMethod:(SEL)name
{
NSLog(@" >> Class resolving %@", NSStringFromSelector(name));
return [super resolveClassMethod:name];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
return [UsrModel instanceMethodSignatureForSelector:aSelector];
}
-(void)Bar
{
NSLog(@" >> Bar() in Foo.");
}
- (NSNumber *)eat
{
NSLog(@"我吃了");
return @43;
}
@end
代码中已附个人整理。
此份总结参考于各个大牛的经验分享。在此,谢谢各位大牛的分享~
最后 附demo: https://github.com/304164084/runtime_demo