zoukankan      html  css  js  c++  java
  • Objective

    在这之前, 我们回想一下, 我们知道实现我们所需要的功能, 就要调用某些方法, 那么这些方法又是怎么样调用的呢? 原理是怎么样的? 让我们一起来探讨一下看看~~



    例子:

    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    - (void)test;
    @end
    
    @implementation Person
    - (void)test
    {
        NSLog(@"调用了test方法");
    }
    @end
    
    int main()
    {
        Person *p = [[Person alloc]init];
        [p test];
        return 0;
    }

    上面这个例子就是我们平常所写的, 那么方法调用的原理是什么??



    1. 把test包装成SEL类型的数据.

    2. 根据SEL数据找到对应方法的地址.

    3. 根据方法地址调用对应的方法.



    这就是方法调用的原理, 在我们所写的每一个方法中, 都会有相应的方法地址, 而SEL的任务就是去找对应方法的地址, 那么示意图是怎么样的呢? 让我们一起来看看:





    那么根据这个, 我们就可以猜猜看, 在调用方法的时候是不是有多种方式呢, 继续往下看:

    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    - (void)test2;
    @end
    
    @implementation Person
    - (void)test2
    {
        NSLog(@"调用了test2方法.");
    }
    @end
    
    int main()
    {
        Person *p = [[Person alloc]init];
        [p test2];
    
        [p performSelector:@selector(test2)];
        return 0;
    }

    结果:

    2015-01-24 21:33:08.046 09-SEL类型[830:48415] 调用了test2方法.
    2015-01-24 21:33:08.047 09-SEL类型[830:48415] 调用了test2方法.
    


    事实证明, 第二种方法也是可以的, 这种是属于间接调用, 那如果添加一个参数呢, 同样也是可以的.

    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    + (void)test;
    - (void)test2;
    - (void)test3:(NSString *)str;
    @end
    
    @implementation Person
    + (void)test
    {
        NSLog(@"调用了test方法.");
    }
    
    - (void)test2
    {
        NSLog(@"调用了test2方法.");
    }
    
    - (void)test3:(NSString *)str
    {
        NSLog(@"test3------%@", str);
    }
    @end
    
    int main() 
    {
    
        Person *p = [[Person alloc]init];
            
        [p test2];
            
        [p performSelector:@selector(test2)];
        
        [p performSelector:@selector(test3:) withObject:@"ABCDEFG"];
    
        return 0;
    }
    

    输出的结果:

    2015-01-24 21:35:58.273 09-SEL类型[844:49833] 调用了test2方法.
    2015-01-24 21:35:58.274 09-SEL类型[844:49833] 调用了test2方法.
    2015-01-24 21:35:58.274 09-SEL类型[844:49833] test3------ABCDEFG
    




    还有几种方法, 比如把字符串转成SEL类型:

    int main() 
    {
    
        Person *p = [[Person alloc]init];
            
        NSString *name = @"test2";
    
        SEl s = NSSelectorFromString(name);
    
        [p performSelector:s];
    
        return 0;
    }

    这样子也是可以调用的.




    再补充一个知识点, 其实每一个方法内部都隐藏着一个SEL的数据, 而且是系统自带的, 叫做_cmd, 下面让我们来看看:

    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    + (void)test;
    - (void)test2;
    @end
    
    @implementation Person
    + (void)test
    {
        NSLog(@"调用了test方法.");
    }
    
    - (void)test2
    {
        NSString *str = NSStringFromSelector(_cmd);
        NSLog(@"调用了test2方法------%@.", str);
    }
    @end
    
    int main() 
    {
    
        Person *p = [[Person alloc]init];
        
        [p test2];    
    
        return 0;
    }
    

    结果:

    2015-01-24 22:10:44.445 09-SEL类型[920:59424] 调用了test2方法---test2.
    

    看到结果之后, 我们就知道了, 在哪个方法里调用_cmd, 那么这个_cmd就指向谁, 也就是代表着当前的这个方法.



    注意, 千万不要在方法里面写一句这样子的代码:

    [self performSelector:_cmd];

    这样子会引发死循环的, 所以千万不能这么写.





    总结一下: SEL其实是对方法的一种包装, 将方法包装成一个SEL类型的数据, 去找对应的方法地址, 找到该方法的地址, 就可以调用该方法了.



    其实也可以这么说, SEL其实也是发送消息的一种, 原因就看上面的例子, 自己慢慢琢磨吧.




    好了, 今天我们就讲到这里, 下次我们继续~~~

  • 相关阅读:
    python学习之路-day1-python基础1
    JSON.NET基本使用
    tortoiseSVN 设置ignore
    一个简单的身份证校验
    一个HttpWebRequest工具类
    linq to NHibernate
    python-plot and networkx绘制网络关系图
    DDoS攻击及防御措施
    白帽子原则
    认识特洛伊木马
  • 原文地址:https://www.cnblogs.com/iOSCain/p/4282831.html
Copyright © 2011-2022 走看看