OC方法调用的四种方式

简介:

  OC中方法调用分为四种方式,如下:

  1. OC代码调用;
  2. NSObject的performSelector调用;
  3. NSInvocation调用;
  4. objc_msgSend即runtime底层方法调用。
      我们最熟悉的当然1和2,我们经常用到,是OC层面上的调用;而3涉及到了方法的动态解析和消息转发机制;4中objc_msgSend调用,是runtime层方法的调用,其实上述的1、2、3到底层runtime层,都是通过objc_msgSend进行调用的,也就是OC的消息发送机制。该篇文章不讲述其它,只是简单对方法调用进行记录和说明。

OC代码调用:

// .h文件
@interface ZBYRunTimePersionModel : NSObject

/// 消息调用的四种方法
- (NSString *)callTestWithStr1:(NSString *)str1 str2:(NSString *)str2 str3:(NSString *)str3;

@end

// .m文件
@implementation ZBYRunTimePersionModel

- (NSString *)callTestWithStr1:(NSString *)str1 str2:(NSString *)str2 str3:(NSString *)str3 {
    NSString * result = [NSString stringWithFormat:@"%@-%@-%@", str1, str2, str3];
    return result;
}

@end

    // OC代码直接调用
    ZBYRunTimePersionModel * person = [ZBYRunTimePersionModel new];
    NSString * r1 = [person callTestWithStr1:@"a" str2:@"b" str3:@"c"];
    NSLog(@"%@", r1);

  最常用的方式,直接调用,缺点不能通过方法名字符串来执行方法。

NSObject的performSelector调用:

    // 2.1用方法调用
    NSString * r21 = [person performSelector:@selector(callTestWithStr1:str2:str3:) withObject:@"a" withObject:@"b"];
    NSLog(@"%@", r21);
    
    // 2.2用方法对应的字符串初始化为方法,再进行调用
    SEL selected = NSSelectorFromString(@"callTestWithStr1:str2:str3:");
    NSString * r22 = [person performSelector:selected withObject:@"a" withObject:@"b"];
    NSLog(@"%@", r22);

  通过NSObject继承的底层方法进行调用;无法进行2个以上参数的传递。

NSInvocation调用:

    /**
     3.NSInvocation调用方法
     3.1进行方法签名;NSMethodSignature的两个参数:numberOfArguments方法参数的个数;methodReturnLength方法返回值类型
        的长度,大于0表示有返回值
     3.2初始化NSInvocation并设置参数
        第一个参数下标为0是target,及响应者;
        第二个参数是selector,及需要调用的方法;
        第三个起是自定义参数,必须传递参数的地址,不能直接传值,例如:str1,str2,str3
     3.3获取返回值;可以在调用invoke前,也可以在invoke之后
     */
    NSMethodSignature * sign = [person methodSignatureForSelector:selected];
    
    // 或者
//    NSMethodSignature * sign = [[self class] instanceMethodSignatureForSelector:selected];
    NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:sign];
    invocation.target = person;
    invocation.selector = selected;
    NSString *arg1 = @"a";
    NSString *arg2 = @"b";
    NSString *arg3 = @"c";
    [invocation setArgument:&arg1 atIndex:2];
    [invocation setArgument:&arg2 atIndex:3];
    [invocation setArgument:&arg3 atIndex:4];
    [invocation invoke];
    if (sign.methodReturnLength > 0) {
        NSString * result = nil;
        [invocation getReturnValue:&result];
        NSLog(@"%@", result);
    }
    else {
        NSLog(@"没有返回值")
    }

  需要对方法进行签名。

objc_msgSend即runtime底层方法调用:

    // 4.第四种方法:底层调用,方法到底层都是通过objc_msgSend调用的,直接用objc_msgSend强制转换进行调用
    
    // 4.1强制转换和调用分开
    void *(*zby_runtime_msgObserverSend)(id, SEL, void *, void *, void *) = (void *)objc_msgSend;
    NSString * r = (__bridge NSString *)(zby_runtime_msgObserverSend(person, selected, @"a", @"b", @"c"));
    NSLog(@"%@", r);
    
    // 4.2强制转换和调用一起
    ((void(*)(id, SEL, void *, void *, void *))objc_msgSend)(person, selected, @"a", @"b", @"c");
//    NSString * r2 = (__bridge NSString *)((void(*)(id, SEL, void *, void *, void *))objc_msgSend)(person, selected, @"a", @"b", @"c");
//    NSLog(@"%@", r2);

你可能感兴趣的:(OC方法调用的四种方式)