转 Objective-C中的isa、class、SEL、IMP

简介:

在objective c中,如果细心的话会发现,每个类中都会自动生成一个class 类型的isa,

?
1
2
3
@interface NSObject <NSObject> {  
      Class    isa;  
  }

isa是什么,class又是什么呢,找到Class的定义我们会发现如下:

?
1
typedefstruct objc_class *Class;


objc_class以前的定义又如下,现在据说被封闭了,不知道有没有再作修改,总之方便我们理解就好:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
struct  objc_class {  
      Class isa;  
        
      Class super_class;     
      const  char  *name;  
      long  version;  
      long  info;    
      long  instance_size;  
      struct  objc_ivar_list *ivars;  
      struct  objc_method_list **methodLists;   
      struct  objc_cache *cache;  
      struct  objc_protocol_list *protocols;     
  }

    于是我们就有了点头绪了,isa,is a pointer,是个指针,每个类都有一个class类型的指针isa,继承自NSObject中,继承关系,方法变量等信息都存放在isa中,isa作为一个隐藏的属性,会自动生成于每个类之中。有了这个前提,也就可以解释为什么我们可以根据@class来代替任意一个类了,看代码:

Human.h

?
1
2
3
4
5
#import <Foundation/Foundation.h>  
   
@interface Human : NSObject  
-( void )say;  
@end

Human.m

?
1
2
3
4
5
6
7
8
#import "Human.h"  
   
@implementation Human  
-( void )say  
{  
     NSLog(@ "Human中的say方法" );  
}  
@end

main.h

?
1
2
3
4
5
6
7
8
9
10
11
12
13
#import <Foundation/Foundation.h>  
#import "Human.h"  
int  main( int  argc,  const  char  * argv[])  
{  
   
     @autoreleasepool {  
           
         Class c =NSClassFromString(@ "Human" );  
         [[c  new ] say];  
         //以上CLASS类型的c,就相当于Human类。  
     }  
     return  0;  
}


    class可以灵活的代替别的类,SEL与其类似,不同的是SEL代替的是方法,可以方便的代替其他方法,class中是因为有isa属性保存有类的信息,而SEL是因为即使是在不同的类中,方法名只要相同,这两个方法的ID就相同,SEL就是根据这个ID来找到该方法,再根据调用该方法的类的不同来找到唯一的地址。

?
1
2
3
4
5
6
7
8
9
typedef  struct  objc_object *id;
 
typedef  struct  objc_selector *SEL;
 
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef  void  (*IMP)( void  /* id, SEL, ... */  ); 
#else
typedef  id (*IMP)(id, SEL, ...); 
#endif

    从上面的头文件中我们可以看到,IMP定义为 id (*IMP) (id, SEL, …)。这样说来, IMP是一个指向函数的指针,这个被指向的函数包括id(“self”指针),调用的SEL(方法名),再加上一些其他参数。 IMP 就是一个函数指针,这个被指向的函数包含一个接收消息的对象id(self  指针), 调用方法的选标 SEL (方法名),以及不定个数的方法参数,并返回一个id。也就是说 IMP 是消息最终调用的执行代码,是方法真正的实现代码 。

?
1
2
3
4
5
6
  # if  !OBJC_OLD_DISPATCH_PROTOTYPES
OBJC_EXPORT  void  objc_msgSend( void  /* id self, SEL op, ... */  )
     __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
OBJC_EXPORT  void  objc_msgSendSuper( void  /* struct objc_super *super, SEL op, ... */  )
     __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
#else


Method

?
1
typedef  struct  objc_method *Method;
?
1
2
3
4
5
6
typedef  struct  objc_method *Method;
struct  objc_method {
   SEL method_name;
   char  *method_types;
   IMP method_imp;
};

    这个定义看上去包括了我们上面说过的其他类型。也就是说,Method(我们常说的方法)表示一种类型,这种类型与selector和实现(implementation)相关。


看代码再作解释:

?
1
2
3
4
5
6
7
8
9
10
11
#import <Foundation/Foundation.h>  
   
@interface Human : NSObject  
-( void )say;  
@end  
@implementation Human  
-( void )say  
{  
     NSLog(@ "Human中的say方法" );  
}  
@end

//上面定义了一个human类,里面有一个say方法  

?
1
2
3
4
5
6
7
8
9
10
11
12
#import <Foundation/Foundation.h>  
 
@interface man:NSObject  
{}  
-( void )say; @end  
   
@implementation man  
-( void )say  
{  
     NSLog(@ "man中的say方法" );  
}  
@end

//在上面定义了一个man类,同样有一个say方法  

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int  main( int  argc,  const  char  * argv[])  
{  
   
     @autoreleasepool {  
           
         Class a =NSClassFromString(@ "Human" );  
         Class b =NSClassFromString(@ "man" );  
         //根据方法名say找到该方法的id,将sel与其绑定;  
         SEL sel = NSSelectorFromString(@ "say" );  
         [[a  new ] performSelector:sel];  
         [[b  new ] performSelector:sel];     
     }  
     return  0;  
}

结果如下:

?
1
2
2012-03-13 10:13:24.900 String[2725:403] Human中的say方法  
2012-03-13 10:13:24.901 String[2725:403] man中的say方法


    通过以上代码我们会发现,SEL通过方法名绑定后,可以被多个类实例调用,找了些网上的资料,解释都是说方法名一样的话,ID会一样,地址仍不同,才会实现这样的效果,我们不谈论是否准确,但我个人认为这是目前最合理的解释。这种用法的优势一方面是灵活性更高,类似于多态,另一方面是,这种用法sel找方法时匹配的是ID而不是字符串方法名,所以在效率上会高一些。还有一种更终极的方法,直接对应方法的地址,这种方法效率最高,请看代码:

?
1
2
3
4
5
6
7
8
9
10
11
#import <Foundation/Foundation.h>  
   
@interface Human : NSObject  
-( void )say;  
@end  
@implementation Human  
-( void )say  
{  
     NSLog(@ "Human中的say方法" );  
}  
@end

//上面定义了一个human类,里面有一个say方法  

?
1
2
3
4
5
6
7
8
9
10
11
12
#import <Foundation/Foundation.h>  
 
@interface man:NSObject  
{}  
-( void )say; @end  
   
@implementation man  
-( void )say  
{  
     NSLog(@ "man中的say方法" );  
}  
@end

//在上面定义了一个man类,同样有一个say方法  

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int  main( int  argc,  const  char  * argv[])  
{  
   
     @autoreleasepool {  
           
         Human *human =[Human  new ];  
         man *ma=[man  new ];  
         //根据方法名say找到该方法的id,将sel与其绑定;  
         SEL sel =@selector(say); //也可以这样写:SEL sel=NSSelectorFromString(@"say");  
         IMP imp1 = [human methodForSelector:sel];       
         IMP imp2 = [ma methodForSelector:sel];       
   
         imp1(human,sel);  
         imp2(ma,sel);  
         //因为每个方法都有自己的地址,这种方式直接找到地址区分相同ID的方法,效率最高,但灵活性不如SEL方式。  
           
     }  
     return  0;  
}

输出语句:

?
1
2
2012-03-13 10:35:21.446 String[3763:403] Human中的say方法  
2012-03-13 10:35:21.450 String[3763:403] man中的say方法


    今天这些内容不太好理解,我用自己理解的方式给大家再解释一遍,class用于代替类,增加灵活性,因为我们不知道什么时候会用到什么类,方法也是如此,所以SEL可以代替方法,每个方法有方法名,ID,地址,相同的方法名,ID也一样,正常情况下我们根据方法名找到方法,用SEL方法可以根据ID找到方法,而用IMP方式可以直接找到地址,但是灵活性不如SEL方法,虽然效率最高。

目录
相关文章
|
开发工具 iOS开发
(7) 引用Objective-C class library
原文 引用Objective-C class library 这个范例是如何在Xamarin.ios中去使用一个我们自行在Xcode中开发的Objective-c Class Library. 主要会执行的步骤如下 在Xcode 里面去建立一个Class Library 编译这个Clas...
1091 0
|
C# iOS开发 程序员
objective-C中的扩展方法与partial class
在c#中要扩展一个现有类很容易,比如这样: public static class Utils { public static void PrintToConsole(this string strSrc) { Console.
758 0
|
C# iOS开发
objective-C中的Class(类类型),Selector(选择器SEL),函数指针(IMP)
今天在园子里看到了一篇牛文“Objective-C 2.0 with Cocoa Foundation--- 5,Class类型,选择器Selector以及函数指针 ”,讲得十分精彩,忍不住把它的代码加上注释整理于此,以便日后查看。
884 0
|
3月前
|
安全 编译器 Swift
IOS开发基础知识: 对比 Swift 和 Objective-C 的优缺点。
IOS开发基础知识: 对比 Swift 和 Objective-C 的优缺点。
93 2
|
3月前
|
安全 JavaScript 前端开发
IOS开发基础知识:介绍一下 Swift 和 Objective-C,它们之间有什么区别?
IOS开发基础知识:介绍一下 Swift 和 Objective-C,它们之间有什么区别?
67 0
|
机器学习/深度学习 API iOS开发
【IOS 开发】Objective-C Foundation 框架 -- 字符串 | 日期 | 对象复制 | NSArray | NSSet | NSDictionary | 谓词(一)
【IOS 开发】Objective-C Foundation 框架 -- 字符串 | 日期 | 对象复制 | NSArray | NSSet | NSDictionary | 谓词(一)
140 0
|
存储 自然语言处理 Java
【IOS 开发】Objective-C Foundation 框架 -- 字符串 | 日期 | 对象复制 | NSArray | NSSet | NSDictionary | 谓词(二)
【IOS 开发】Objective-C Foundation 框架 -- 字符串 | 日期 | 对象复制 | NSArray | NSSet | NSDictionary | 谓词(二)
218 0
|
Java iOS开发
【iOS 开发】Objective - C 面向对象 - 方法 | 成员变量 | 隐藏封装 | KVC | KVO | 初始化 | 多态(二)
【iOS 开发】Objective - C 面向对象 - 方法 | 成员变量 | 隐藏封装 | KVC | KVO | 初始化 | 多态(二)
116 0