iOS 函数调用的流程

OC是一门动态语言,一个函数是由一个selector(SEL),和一个implement(IML)组成的。selector相当于地址,而implement才是真正的房间。和我们网购一样,地址可以随意写。但不一定都能找到收件人。如果找不到系统会给程序几次机会来使程序正常运行,之后依然不行才会抛出异常。

下面用代码来实际演示一下。建议每个方法都打上断点,这样能够理解函数的执行顺序。

#import "RunTimeTest.h"
#import <objc/runtime.h>

@interface RunTimeChild : NSObject


@end

@implementation RunTimeChild

- (void)resolveThisMethodDynamically2
{
    NSLog(@"resolveThisMethodDynamically");
}

@end

@interface RunTimeTest()


@end

@implementation RunTimeTest
@dynamic name ,age;
- (id)init
{
    if (self = [super init]) {
        _mutableDic = [NSMutableDictionary dictionary];
        [_mutableDic setObject:@"bnm" forKey:@"uio"];
        [_mutableDic setObject:@"xiaoming" forKey:@"name"];
    }
    return self;
}
void dynamicMethodIMP(id self,SEL _cmd)
{
    NSLog(@"dynamicMethodIMP");
}

/*
 * 这个函数在当前类执行时没有找到对应的SEL的IML时就会执行,这个函数是给类利用class_addMethod动态添加函数的机会
 * 如果实现了添加函数代码则返回YES,否则返回NO。
 * 提醒下这里是否继续执行之后的流程不是以resolveInstanceMethod返回值为准的,而是以是否找到对应SEL为标准
 */

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    if (sel == @selector(resolveThisMethodDynamically)) {
        class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "v@:");
    }
    return YES;
}

/*
 执行到这个函数,系统将给了个将这个SEL转给其他对象的机会
 返回参数一个对象,如果这个对象非空,非self,系统会将运行的消息转发给这个对象执行。
 */
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    RunTimeChild *child = [[RunTimeChild alloc] init];
    //return child;   //取消注释会将SEL转移至这个对象中
    return nil;
}

/*
 这个函数与forwardInvocation是最后寻找SEL的机会。这个函数让重载方有机会抛出一个函数的签名,再由后面的forwardInvocation去执行
 */
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSString *sel = NSStringFromSelector(aSelector);
    if ([sel rangeOfString:@"set"].location == 0) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    }else{
        return [NSMethodSignature signatureWithObjCTypes:"@@:"];
    }
    
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSString *key = NSStringFromSelector([anInvocation selector]);
    if ([key rangeOfString:@"set"].location == 0) {
        key = [[key substringWithRange:NSMakeRange(3, [key length] - 4)] lowercaseString];
        NSString *obj;
        [anInvocation getArgument:&obj atIndex:2];
        NSLog(@"%@",obj);
        [_mutableDic setObject:obj forKey:key];
    }else{
        NSString *obj = [_mutableDic objectForKey:key];
        NSLog(@"%@",key);
        [anInvocation setReturnValue:&obj];
    }
    
    
}


@end

调用方法:

#import "ViewController.h"
#import "RunTimeTest.h"
#import <objc/runtime.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    RunTimeTest *runTime = [[RunTimeTest alloc] init];
//    SEL S = NSSelectorFromString(@"uio");
    runTime.age = @"18";
    NSString *f = [runTime age];
    NSLog(@"%@",f);
    
//    objc_msgSend((id)runTime,S);
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end


代码下载:http://download.csdn.net/detail/qqmcy/9450669


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杜甲同学

感谢打赏,我会继续努力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值